From 40195b58d657f3f332d3d8daafaed89acf648cc8 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Wed, 22 Oct 2025 21:00:06 +0200 Subject: [PATCH 01/16] feat: Use `QScrollArea` for components selection --- package/PartSeg/_roi_mask/main_window.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/package/PartSeg/_roi_mask/main_window.py b/package/PartSeg/_roi_mask/main_window.py index c3b7d4bad..0989c7fbe 100644 --- a/package/PartSeg/_roi_mask/main_window.py +++ b/package/PartSeg/_roi_mask/main_window.py @@ -16,6 +16,7 @@ QMessageBox, QProgressBar, QPushButton, + QScrollArea, QSizePolicy, QSpinBox, QTabWidget, @@ -527,6 +528,12 @@ def __init__(self, settings: StackSettings, image_view: StackImageView): # noqa self.choose_components.check_change_signal.connect(image_view.refresh_selected) self.choose_components.mouse_leave.connect(image_view.component_unmark) self.choose_components.mouse_enter.connect(image_view.component_mark) + self.choose_components_wrapper = QScrollArea() + self.choose_components_wrapper.setWidget(self.choose_components) + self.choose_components_wrapper.setWidgetResizable(True) + self.choose_components_wrapper.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.choose_components_wrapper.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) + self.chosen_list = [] self.progress_bar2 = QProgressBar() self.progress_bar2.setHidden(True) @@ -567,7 +574,7 @@ def __init__(self, settings: StackSettings, image_view: StackImageView): # noqa main_layout.addWidget(self.progress_bar) main_layout.addWidget(self.progress_info_lab) main_layout.addWidget(self.algorithm_choose_widget, 1) - main_layout.addWidget(self.choose_components) + main_layout.addWidget(self.choose_components_wrapper) down_layout = QHBoxLayout() down_layout.addWidget(self.keep_chosen_components_chk) down_layout.addWidget(self.show_parameters) From 4c1a8c339d7b69bef6bad06d1d684680369253f8 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Thu, 19 Mar 2026 14:10:44 +0100 Subject: [PATCH 02/16] fix setting roi in StackSettings --- package/PartSeg/_roi_mask/stack_settings.py | 11 +++++------ package/PartSeg/common_backend/base_settings.py | 4 ++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/package/PartSeg/_roi_mask/stack_settings.py b/package/PartSeg/_roi_mask/stack_settings.py index 3ca23664f..685bfa44d 100644 --- a/package/PartSeg/_roi_mask/stack_settings.py +++ b/package/PartSeg/_roi_mask/stack_settings.py @@ -304,18 +304,17 @@ def _set_roi_info( raise ValueError("ROI do not fit to image") from e if save_chosen: state2 = self.transform_state(state, new_roi_info, segmentation_parameters, list_of_components, save_chosen) - self.chosen_components_widget.set_chose( - sorted(state2.roi_extraction_parameters.keys()), state2.selected_components - ) self.roi = state2.roi_info + self.chosen_components_widget.set_chosen(state2.selected_components) self.components_parameters_dict = state2.roi_extraction_parameters else: - selected_parameters = {i: segmentation_parameters[i] for i in new_roi_info.bound_info} - - self.chosen_components_widget.set_chose(sorted(selected_parameters.keys()), list_of_components) self.roi = new_roi_info + self.chosen_components_widget.set_chosen(list_of_components) self.components_parameters_dict = segmentation_parameters + def post_roi_set(self): + self.chosen_components_widget.set_chose(self.roi_info.bound_info.keys(), []) + def get_mask( segmentation: typing.Optional[np.ndarray], mask: typing.Optional[np.ndarray], selected: list[int] diff --git a/package/PartSeg/common_backend/base_settings.py b/package/PartSeg/common_backend/base_settings.py index c19959643..0cd5b1087 100644 --- a/package/PartSeg/common_backend/base_settings.py +++ b/package/PartSeg/common_backend/base_settings.py @@ -155,8 +155,12 @@ def roi(self, val: Union[np.ndarray, ROIInfo]): except ValueError as e: raise ValueError(ROI_NOT_FIT) from e self._additional_layers = {} + self.post_roi_set() self.roi_changed.emit(self._roi_info) + def post_roi_set(self) -> None: + """called after roi is set, for subclasses to override""" + @property def sizes(self): return self._roi_info.sizes From 6fb5071c1f3c0d69dc0550e0d2d476652de8ea17 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Thu, 19 Mar 2026 14:20:42 +0100 Subject: [PATCH 03/16] Make `ChosenComponents`subclass of `QScrollArea` --- package/PartSeg/_roi_mask/main_window.py | 28 ++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/package/PartSeg/_roi_mask/main_window.py b/package/PartSeg/_roi_mask/main_window.py index 0989c7fbe..67cf503a8 100644 --- a/package/PartSeg/_roi_mask/main_window.py +++ b/package/PartSeg/_roi_mask/main_window.py @@ -1,6 +1,8 @@ import os +from collections.abc import Sequence from contextlib import suppress from functools import partial +from typing import Union import numpy as np from qtpy.QtCore import QByteArray, Qt, Signal, Slot @@ -394,7 +396,7 @@ def leaveEvent(self, _event): self.mouse_leave.emit(self.number) -class ChosenComponents(QWidget): +class ChosenComponents(QScrollArea): """ :type check_box: dict[int, ComponentCheckBox] """ @@ -405,6 +407,7 @@ class ChosenComponents(QWidget): def __init__(self): super().__init__() + self.setWidget(QWidget(self)) self.check_box = {} self.check_all_btn = QPushButton("Select all") self.check_all_btn.clicked.connect(self.check_all) @@ -417,11 +420,15 @@ def __init__(self): self.check_layout = FlowLayout() main_layout.addLayout(btn_layout) main_layout.addLayout(self.check_layout) - self.setLayout(main_layout) + self.widget().setLayout(main_layout) + self.setWidgetResizable(True) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) def other_component_choose(self, num): check = self.check_box[num] check.setChecked(not check.isChecked()) + self.ensureWidgetVisible(check) def check_all(self): for el in self.check_box.values(): @@ -443,7 +450,9 @@ def remove_components(self): def new_choose(self, num, chosen_components): self.set_chose(range(1, num + 1), chosen_components) - def set_chose(self, components_index, chosen_components): + def set_chose(self, components_index, chosen_components: Union[Sequence[int], None] = None): + if chosen_components is None: + chosen_components = [] chosen_components = set(chosen_components) self.blockSignals(True) self.remove_components() @@ -460,11 +469,17 @@ def set_chose(self, components_index, chosen_components): self.update() self.check_change_signal.emit() + def set_chosen(self, chosen_components: Sequence[int]): + chosen_components = set(chosen_components) + for num, check in self.check_box.items(): + check.setChecked(num in chosen_components) + def check_change(self): self.check_change_signal.emit() def change_state(self, num, val): self.check_box[num].setChecked(val) + self.ensureWidgetVisible(self.check_box[num]) def get_state(self, num: int) -> bool: # TODO Check what situation create report of id ID: af9b57f074264169b4353aa1e61d8bc2 @@ -528,11 +543,6 @@ def __init__(self, settings: StackSettings, image_view: StackImageView): # noqa self.choose_components.check_change_signal.connect(image_view.refresh_selected) self.choose_components.mouse_leave.connect(image_view.component_unmark) self.choose_components.mouse_enter.connect(image_view.component_mark) - self.choose_components_wrapper = QScrollArea() - self.choose_components_wrapper.setWidget(self.choose_components) - self.choose_components_wrapper.setWidgetResizable(True) - self.choose_components_wrapper.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) - self.choose_components_wrapper.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded) self.chosen_list = [] self.progress_bar2 = QProgressBar() @@ -574,7 +584,7 @@ def __init__(self, settings: StackSettings, image_view: StackImageView): # noqa main_layout.addWidget(self.progress_bar) main_layout.addWidget(self.progress_info_lab) main_layout.addWidget(self.algorithm_choose_widget, 1) - main_layout.addWidget(self.choose_components_wrapper) + main_layout.addWidget(self.choose_components) down_layout = QHBoxLayout() down_layout.addWidget(self.keep_chosen_components_chk) down_layout.addWidget(self.show_parameters) From 6744bd9fc735eb7f782c248264f47d10f758b5eb Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Thu, 19 Mar 2026 14:44:50 +0100 Subject: [PATCH 04/16] Use splitter for adjust ui --- package/PartSeg/_roi_mask/main_window.py | 7 +++++-- package/PartSeg/common_gui/napari_image_view.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/package/PartSeg/_roi_mask/main_window.py b/package/PartSeg/_roi_mask/main_window.py index 67cf503a8..4724186d2 100644 --- a/package/PartSeg/_roi_mask/main_window.py +++ b/package/PartSeg/_roi_mask/main_window.py @@ -5,6 +5,7 @@ from typing import Union import numpy as np +from PyQt6.QtWidgets import QSplitter from qtpy.QtCore import QByteArray, Qt, Signal, Slot from qtpy.QtGui import QCloseEvent, QGuiApplication, QIcon, QKeySequence, QTextOption from qtpy.QtWidgets import ( @@ -583,8 +584,10 @@ def __init__(self, settings: StackSettings, image_view: StackImageView): # noqa main_layout.addWidget(self.progress_bar2) main_layout.addWidget(self.progress_bar) main_layout.addWidget(self.progress_info_lab) - main_layout.addWidget(self.algorithm_choose_widget, 1) - main_layout.addWidget(self.choose_components) + split = QSplitter(Qt.Orientation.Vertical) + split.addWidget(self.algorithm_choose_widget) + split.addWidget(self.choose_components) + main_layout.addWidget(split, 1) down_layout = QHBoxLayout() down_layout.addWidget(self.keep_chosen_components_chk) down_layout.addWidget(self.show_parameters) diff --git a/package/PartSeg/common_gui/napari_image_view.py b/package/PartSeg/common_gui/napari_image_view.py index 95843f16f..2272f16fb 100644 --- a/package/PartSeg/common_gui/napari_image_view.py +++ b/package/PartSeg/common_gui/napari_image_view.py @@ -584,7 +584,7 @@ def _remove_worker(self, sender=None): else: logging.debug("[_remove_worker] %s", sender) - def _add_layer_util(self, index, layer, filters): + def _add_layer_util(self, index: int, layer: _NapariImage, filters: list[tuple[NoiseFilterType, float]]) -> None: if layer not in self.viewer.layers: self.viewer.add_layer(layer) From a107e420168b705c835eae5e6572658f0341e776 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Thu, 19 Mar 2026 14:48:53 +0100 Subject: [PATCH 05/16] fix qt import --- package/PartSeg/_roi_mask/main_window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/PartSeg/_roi_mask/main_window.py b/package/PartSeg/_roi_mask/main_window.py index 4724186d2..282673daa 100644 --- a/package/PartSeg/_roi_mask/main_window.py +++ b/package/PartSeg/_roi_mask/main_window.py @@ -5,7 +5,6 @@ from typing import Union import numpy as np -from PyQt6.QtWidgets import QSplitter from qtpy.QtCore import QByteArray, Qt, Signal, Slot from qtpy.QtGui import QCloseEvent, QGuiApplication, QIcon, QKeySequence, QTextOption from qtpy.QtWidgets import ( @@ -22,6 +21,7 @@ QScrollArea, QSizePolicy, QSpinBox, + QSplitter, QTabWidget, QTextEdit, QVBoxLayout, From 62789632fae263076188556f16f698502ccd4eb3 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Thu, 19 Mar 2026 19:19:39 +0100 Subject: [PATCH 06/16] fix settings --- package/PartSeg/_roi_mask/stack_settings.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/package/PartSeg/_roi_mask/stack_settings.py b/package/PartSeg/_roi_mask/stack_settings.py index 685bfa44d..a212e958c 100644 --- a/package/PartSeg/_roi_mask/stack_settings.py +++ b/package/PartSeg/_roi_mask/stack_settings.py @@ -170,17 +170,15 @@ def set_project_info(self, data: typing.Union[MaskProjectTuple, PointsInfo]): data.selected_components, self.keep_chosen_components, ) - self.chosen_components_widget.set_chose( - sorted(state2.roi_extraction_parameters.keys()), state2.selected_components - ) self.roi = state2.roi_info + self.chosen_components_widget.set_chosen(state2.selected_components) + self.components_parameters_dict = state2.roi_extraction_parameters else: self.set_history(data.history) - self.chosen_components_widget.set_chose( - sorted(data.roi_extraction_parameters.keys()), data.selected_components - ) self.roi = data.roi_info + self.chosen_components_widget.set_chosen(data.selected_components) + self.components_parameters_dict = data.roi_extraction_parameters @staticmethod From 01dccd9ef10aae7f061ce80c390a9c749c148584 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Fri, 20 Mar 2026 13:00:02 +0100 Subject: [PATCH 07/16] fix `BaseSettings.roi` setter --- package/PartSeg/common_backend/base_settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/package/PartSeg/common_backend/base_settings.py b/package/PartSeg/common_backend/base_settings.py index 0cd5b1087..36741db95 100644 --- a/package/PartSeg/common_backend/base_settings.py +++ b/package/PartSeg/common_backend/base_settings.py @@ -145,6 +145,7 @@ def roi(self, val: Union[np.ndarray, ROIInfo]): if val is None: self._roi_info = ROIInfo(val) self._additional_layers = {} + self.post_roi_set() self.roi_clean.emit() return try: From 81e0f0bc5a217baa3309aa66a8c5762592908c71 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Fri, 20 Mar 2026 13:12:13 +0100 Subject: [PATCH 08/16] ensure `post_roi_set` correctness --- package/PartSeg/_roi_mask/stack_settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package/PartSeg/_roi_mask/stack_settings.py b/package/PartSeg/_roi_mask/stack_settings.py index a212e958c..1bc7737b3 100644 --- a/package/PartSeg/_roi_mask/stack_settings.py +++ b/package/PartSeg/_roi_mask/stack_settings.py @@ -311,7 +311,8 @@ def _set_roi_info( self.components_parameters_dict = segmentation_parameters def post_roi_set(self): - self.chosen_components_widget.set_chose(self.roi_info.bound_info.keys(), []) + if self.chosen_components_widget is not None: + self.chosen_components_widget.set_chosen(self.components_parameters_dict) def get_mask( From 6b3bc30794937ca351fd7077b0cb5dddd254d097 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Fri, 20 Mar 2026 13:50:19 +0100 Subject: [PATCH 09/16] do not emit signal during update list of connections --- package/PartSeg/_roi_mask/main_window.py | 9 +++++---- package/PartSeg/_roi_mask/stack_settings.py | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package/PartSeg/_roi_mask/main_window.py b/package/PartSeg/_roi_mask/main_window.py index 282673daa..650c11951 100644 --- a/package/PartSeg/_roi_mask/main_window.py +++ b/package/PartSeg/_roi_mask/main_window.py @@ -448,10 +448,10 @@ def remove_components(self): el.mouse_enter.disconnect() self.check_box.clear() - def new_choose(self, num, chosen_components): - self.set_chose(range(1, num + 1), chosen_components) + def new_choose(self, num: int, chosen_components: Sequence[int]) -> None: + self.set_components(range(1, num + 1), chosen_components) - def set_chose(self, components_index, chosen_components: Union[Sequence[int], None] = None): + def set_components(self, components_index, chosen_components: Union[Sequence[int], None] = None): if chosen_components is None: chosen_components = [] chosen_components = set(chosen_components) @@ -474,6 +474,7 @@ def set_chosen(self, chosen_components: Sequence[int]): chosen_components = set(chosen_components) for num, check in self.check_box.items(): check.setChecked(num in chosen_components) + self.check_change_signal.emit() def check_change(self): self.check_change_signal.emit() @@ -679,7 +680,7 @@ def segmentation(self, val): def _image_changed(self): self.settings.roi = None - self.choose_components.set_chose([], []) + self.choose_components.set_components([], []) def _execute_in_background_init(self): if self.batch_process.isRunning(): diff --git a/package/PartSeg/_roi_mask/stack_settings.py b/package/PartSeg/_roi_mask/stack_settings.py index 1bc7737b3..486f7fda1 100644 --- a/package/PartSeg/_roi_mask/stack_settings.py +++ b/package/PartSeg/_roi_mask/stack_settings.py @@ -312,7 +312,8 @@ def _set_roi_info( def post_roi_set(self): if self.chosen_components_widget is not None: - self.chosen_components_widget.set_chosen(self.components_parameters_dict) + with self.components_change_list.blockSignals(True): + self.chosen_components_widget.set_components(self.components_parameters_dict) def get_mask( From 590b71ecb464dd75bf456ae3bb0db97036458234 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Fri, 20 Mar 2026 14:27:41 +0100 Subject: [PATCH 10/16] proper block --- package/PartSeg/_roi_mask/stack_settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package/PartSeg/_roi_mask/stack_settings.py b/package/PartSeg/_roi_mask/stack_settings.py index 486f7fda1..c9eaec938 100644 --- a/package/PartSeg/_roi_mask/stack_settings.py +++ b/package/PartSeg/_roi_mask/stack_settings.py @@ -312,8 +312,11 @@ def _set_roi_info( def post_roi_set(self): if self.chosen_components_widget is not None: - with self.components_change_list.blockSignals(True): + prev = self.chosen_components_widget.blockSignals(True) + try: self.chosen_components_widget.set_components(self.components_parameters_dict) + finally: + self.chosen_components_widget.blockSignals(prev) def get_mask( From aaf4ad1b8aec670ac371a1cf1f6fc19ba99aa353 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Sat, 21 Mar 2026 00:20:02 +0100 Subject: [PATCH 11/16] fix code --- package/PartSeg/_roi_mask/stack_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/PartSeg/_roi_mask/stack_settings.py b/package/PartSeg/_roi_mask/stack_settings.py index c9eaec938..d5acc9de1 100644 --- a/package/PartSeg/_roi_mask/stack_settings.py +++ b/package/PartSeg/_roi_mask/stack_settings.py @@ -314,7 +314,7 @@ def post_roi_set(self): if self.chosen_components_widget is not None: prev = self.chosen_components_widget.blockSignals(True) try: - self.chosen_components_widget.set_components(self.components_parameters_dict) + self.chosen_components_widget.set_components(self.roi_info.bound_info.keys(), []) finally: self.chosen_components_widget.blockSignals(prev) From b04c7500a4ec0d97ee9b91af5da9d7061e91273c Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Mon, 23 Mar 2026 21:19:37 +0100 Subject: [PATCH 12/16] fix set_segmentation_result --- package/PartSeg/common_backend/base_settings.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package/PartSeg/common_backend/base_settings.py b/package/PartSeg/common_backend/base_settings.py index 36741db95..324ca5b0d 100644 --- a/package/PartSeg/common_backend/base_settings.py +++ b/package/PartSeg/common_backend/base_settings.py @@ -535,8 +535,7 @@ def set_segmentation_result(self, result: ROIExtractionResult): raise ValueError(ROI_NOT_FIT) from e if result.points is not None: self.points = result.points - self._roi_info = roi_info - self.roi_changed.emit(self._roi_info) + self.roi = roi_info def _load_files_call(self, files_list: list[str]): self.request_load_files.emit(files_list) From 20391806b327d0c35014326f821f365767f35826 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Mon, 23 Mar 2026 21:31:59 +0100 Subject: [PATCH 13/16] deduplicate signals --- package/PartSeg/_roi_mask/main_window.py | 26 ++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/package/PartSeg/_roi_mask/main_window.py b/package/PartSeg/_roi_mask/main_window.py index 650c11951..f1b6d5be7 100644 --- a/package/PartSeg/_roi_mask/main_window.py +++ b/package/PartSeg/_roi_mask/main_window.py @@ -432,12 +432,22 @@ def other_component_choose(self, num): self.ensureWidgetVisible(check) def check_all(self): - for el in self.check_box.values(): - el.setChecked(True) + prev = self.blockSignals(True) + try: + for el in self.check_box.values(): + el.setChecked(True) + finally: + self.blockSignals(prev) + self.check_change_signal.emit() def un_check_all(self): - for el in self.check_box.values(): - el.setChecked(False) + prev = self.blockSignals(True) + try: + for el in self.check_box.values(): + el.setChecked(False) + finally: + self.blockSignals(prev) + self.check_change_signal.emit() def remove_components(self): self.check_layout.clear() @@ -471,9 +481,13 @@ def set_components(self, components_index, chosen_components: Union[Sequence[int self.check_change_signal.emit() def set_chosen(self, chosen_components: Sequence[int]): + prev = self.blockSignals(True) chosen_components = set(chosen_components) - for num, check in self.check_box.items(): - check.setChecked(num in chosen_components) + try: + for num, check in self.check_box.items(): + check.setChecked(num in chosen_components) + finally: + self.blockSignals(prev) self.check_change_signal.emit() def check_change(self): From f10f16be709240320aa501661f6ee6c1c5e3e1af Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Mon, 23 Mar 2026 21:39:06 +0100 Subject: [PATCH 14/16] Put `ImageSettings.roi` setter next to getter --- package/PartSeg/common_backend/base_settings.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package/PartSeg/common_backend/base_settings.py b/package/PartSeg/common_backend/base_settings.py index 324ca5b0d..ed59ec022 100644 --- a/package/PartSeg/common_backend/base_settings.py +++ b/package/PartSeg/common_backend/base_settings.py @@ -126,11 +126,6 @@ def segmentation(self) -> np.ndarray: # pragma: no cover warnings.warn("segmentation parameter is renamed to roi", DeprecationWarning, stacklevel=2) return self.roi - @property - def roi(self) -> np.ndarray: - """current roi""" - return self._roi_info.roi - @property def segmentation_info(self) -> ROIInfo: # pragma: no cover warnings.warn("segmentation info parameter is renamed to roi", DeprecationWarning, stacklevel=2) @@ -140,6 +135,11 @@ def segmentation_info(self) -> ROIInfo: # pragma: no cover def roi_info(self) -> ROIInfo: return self._roi_info + @property + def roi(self) -> np.ndarray: + """current roi""" + return self._roi_info.roi + @roi.setter def roi(self, val: Union[np.ndarray, ROIInfo]): if val is None: From abc1a2123ffb7df07fdf0798835dd52e30df866c Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Mon, 23 Mar 2026 22:26:08 +0100 Subject: [PATCH 15/16] better blocking signals in `set_components` --- package/PartSeg/_roi_mask/main_window.py | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/package/PartSeg/_roi_mask/main_window.py b/package/PartSeg/_roi_mask/main_window.py index f1b6d5be7..98d29ddcf 100644 --- a/package/PartSeg/_roi_mask/main_window.py +++ b/package/PartSeg/_roi_mask/main_window.py @@ -465,18 +465,20 @@ def set_components(self, components_index, chosen_components: Union[Sequence[int if chosen_components is None: chosen_components = [] chosen_components = set(chosen_components) - self.blockSignals(True) - self.remove_components() - for el in components_index: - check = ComponentCheckBox(el) - if el in chosen_components: - check.setChecked(True) - check.stateChanged.connect(self.check_change) - check.mouse_enter.connect(self.mouse_enter.emit) - check.mouse_leave.connect(self.mouse_leave.emit) - self.check_box[el] = check - self.check_layout.addWidget(check) - self.blockSignals(False) + prev = self.blockSignals(True) + try: + self.remove_components() + for el in components_index: + check = ComponentCheckBox(el) + if el in chosen_components: + check.setChecked(True) + check.stateChanged.connect(self.check_change) + check.mouse_enter.connect(self.mouse_enter.emit) + check.mouse_leave.connect(self.mouse_leave.emit) + self.check_box[el] = check + self.check_layout.addWidget(check) + finally: + self.blockSignals(prev) self.update() self.check_change_signal.emit() From a14af5a5ea41b2c0cdb8c0f1a18a158bab722740 Mon Sep 17 00:00:00 2001 From: Grzegorz Bokota Date: Mon, 23 Mar 2026 23:25:25 +0100 Subject: [PATCH 16/16] remove double fiting roi --- package/PartSeg/common_backend/base_settings.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/package/PartSeg/common_backend/base_settings.py b/package/PartSeg/common_backend/base_settings.py index ed59ec022..16ae8d910 100644 --- a/package/PartSeg/common_backend/base_settings.py +++ b/package/PartSeg/common_backend/base_settings.py @@ -529,13 +529,9 @@ def set_segmentation_result(self, result: ROIExtractionResult): self.last_executed_algorithm = result.parameters.algorithm self.set_algorithm(f"algorithms.{result.parameters.algorithm}", result.parameters.values) # Fixme not use EventedDict here - try: - roi_info = result.roi_info.fit_to_image(self.image) - except ValueError as e: # pragma: no cover - raise ValueError(ROI_NOT_FIT) from e + self.roi = result.roi_info if result.points is not None: self.points = result.points - self.roi = roi_info def _load_files_call(self, files_list: list[str]): self.request_load_files.emit(files_list)