Skip to content

Commit c60e695

Browse files
committed
Subclass SegmentationMethod definition in protocol config (#318)
This commit subclasses the `SegmentationMethod` configurer to account for the unique inheritance structure of `SegmentationMethods`. In brief, there are three levels of inheritance, but the last two levels are supposed to be alternative selections. Between the alternative selections, two of them (`UniformWater` and `UniformTissue`) are supposed to be the same as `UniformSegmentation` except that `ref_material` is set as water/tissue and is not intended to be mutable. The subclassing of the definition form takes all these details into account. [See the discussion on GitHub here.](OpenwaterHealth/OpenLIFU-python#289 (comment))
1 parent f06e26e commit c60e695

File tree

3 files changed

+87
-11
lines changed

3 files changed

+87
-11
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
openlifu==0.3.1
1+
git+https://github.com/OpenwaterHealth/OpenLIFU-python.git@0e09d41ae8eb862319de0598187687db21b3081b
22
bcrypt

OpenLIFUProtocolConfig/OpenLIFUProtocolConfig.py

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Standard library imports
22
from enum import Enum
33
from pathlib import Path
4+
import types
45
from typing import (
56
List,
67
Optional,
@@ -257,8 +258,8 @@ def setup(self) -> None:
257258
self.abstract_apodization_method_definition_widget = OpenLIFUAbstractApodizationMethodDefinitionFormWidget()
258259
replace_widget(self.ui.abstractApodizationMethodDefinitionWidgetPlaceholder, self.abstract_apodization_method_definition_widget, self.ui)
259260

260-
self.segmentation_method_definition_widget = OpenLIFUAbstractDataclassDefinitionFormWidget(cls=openlifu_lz().seg.SegmentationMethod, parent=self.ui.segmentationMethodDefinitionWidgetPlaceholder.parentWidget(), collapsible_title="Segmentation Method")
261-
replace_widget(self.ui.segmentationMethodDefinitionWidgetPlaceholder, self.segmentation_method_definition_widget, self.ui)
261+
self.abstract_segmentation_method_definition_widget = OpenLIFUAbstractSegmentationMethodDefinitionFormWidget()
262+
replace_widget(self.ui.abstractSegmentationMethodDefinitionWidgetPlaceholder, self.abstract_segmentation_method_definition_widget, self.ui)
262263

263264
self.parameter_constraints_widget = OpenLIFUParameterConstraintsWidget()
264265
replace_widget(self.ui.parameterConstraintsWidgetPlaceholder, self.parameter_constraints_widget, self.ui)
@@ -301,7 +302,7 @@ def setup(self) -> None:
301302
self.sim_setup_definition_widget.add_value_changed_signals(trigger_unsaved_changes)
302303
self.abstract_delay_method_definition_widget.add_value_changed_signals(trigger_unsaved_changes)
303304
self.abstract_apodization_method_definition_widget.add_value_changed_signals(trigger_unsaved_changes)
304-
self.segmentation_method_definition_widget.add_value_changed_signals(trigger_unsaved_changes)
305+
self.abstract_segmentation_method_definition_widget.add_value_changed_signals(trigger_unsaved_changes)
305306
self.parameter_constraints_widget.table.itemChanged.connect(lambda *_: trigger_unsaved_changes())
306307
self.target_constraints_widget.table.itemChanged.connect(lambda *_: trigger_unsaved_changes())
307308
self.solution_analysis_options_definition_widget.add_value_changed_signals(trigger_unsaved_changes)
@@ -655,7 +656,7 @@ def updateProtocolDisplayFromProtocol(self, protocol: "openlifu.plan.Protocol"):
655656
self.sim_setup_definition_widget.update_form_from_class(protocol.sim_setup)
656657
self.abstract_delay_method_definition_widget.update_form_from_class(protocol.delay_method)
657658
self.abstract_apodization_method_definition_widget.update_form_from_class(protocol.apod_method)
658-
self.segmentation_method_definition_widget.update_form_from_class(protocol.seg_method)
659+
self.abstract_segmentation_method_definition_widget.update_form_from_class(protocol.seg_method)
659660
self.parameter_constraints_widget.from_dict(protocol.param_constraints)
660661
self.target_constraints_widget.from_list(protocol.target_constraints)
661662
self.solution_analysis_options_definition_widget.update_form_from_class(protocol.analysis_options)
@@ -694,7 +695,7 @@ def getProtocolFromGUI(self) -> "openlifu.plan.Protocol":
694695
sim_setup = self.sim_setup_definition_widget.get_form_as_class()
695696
delay_method = self.abstract_delay_method_definition_widget.get_form_as_class()
696697
apodization_method = self.abstract_apodization_method_definition_widget.get_form_as_class()
697-
segmentation_method = self.segmentation_method_definition_widget.get_form_as_class()
698+
segmentation_method = self.abstract_segmentation_method_definition_widget.get_form_as_class()
698699
parameter_constraints = self.parameter_constraints_widget.to_dict()
699700
target_constraints = self.target_constraints_widget.to_list()
700701
solution_analysis_options = self.solution_analysis_options_definition_widget.get_form_as_class()
@@ -737,7 +738,7 @@ def setProtocolEditorEnabled(self, enabled: bool) -> None:
737738
self.sim_setup_definition_widget.setEnabled(enabled)
738739
self.abstract_delay_method_definition_widget.setEnabled(enabled)
739740
self.abstract_apodization_method_definition_widget.setEnabled(enabled)
740-
self.segmentation_method_definition_widget.setEnabled(enabled)
741+
self.abstract_segmentation_method_definition_widget.setEnabled(enabled)
741742
self.parameter_constraints_widget.setEnabled(enabled)
742743
self.target_constraints_widget.setEnabled(enabled)
743744
self.solution_analysis_options_definition_widget.setEnabled(enabled)
@@ -926,7 +927,7 @@ def get_default_apodization_method(cls):
926927

927928
@classmethod
928929
def get_default_segmentation_method(cls):
929-
return openlifu_lz().seg.seg_methods.Water()
930+
return openlifu_lz().seg.seg_methods.UniformWater()
930931

931932
@classmethod
932933
def get_default_parameter_constraints(cls):
@@ -1061,6 +1062,81 @@ def __init__(self):
10611062
max_angle_spinbox = maxangle_definition_form_widget._field_widgets['max_angle']
10621063
maxangle_definition_form_widget.modify_widget_spinbox(max_angle_spinbox, default_value=30, min_value=0, max_value=90)
10631064

1065+
def _get_form_as_segmentation_method(self):
1066+
"""
1067+
Custom replacement for get_form_as_class, used to override
1068+
widgets inside the segmentation method form.
1069+
"""
1070+
d = self.get_form_as_dict()
1071+
1072+
# Remove ref_material if class is UniformWater or UniformTissue
1073+
if self._cls.__name__ in ["UniformWater", "UniformTissue"]:
1074+
d.pop("ref_material")
1075+
1076+
return self._cls(**d)
1077+
1078+
class OpenLIFUAbstractSegmentationMethodDefinitionFormWidget(OpenLIFUAbstractMultipleABCDefinitionFormWidget):
1079+
1080+
1081+
def __init__(self):
1082+
"""
1083+
Overwrite of __init__ that mimics most of super()'s behavior, except
1084+
accounts for the unique inheritance structure of SegmentationMethod.
1085+
"""
1086+
# ---- Begin constructor overwrite ----
1087+
1088+
cls_list = [openlifu_lz().seg.seg_methods.UniformSegmentation, openlifu_lz().seg.seg_methods.UniformTissue, openlifu_lz().seg.seg_methods.UniformWater]
1089+
is_collapsible = False
1090+
parent: Optional[qt.QWidget] = None
1091+
collapsible_title = "Segmentation Method"
1092+
custom_abc_title = "Segmentation Method"
1093+
1094+
self.cls_list = cls_list
1095+
self.base_class_name = cls_list[0].__bases__[0].__name__
1096+
self.custom_abc_title = self.base_class_name if custom_abc_title is None else custom_abc_title
1097+
1098+
qt.QWidget.__init__(self, parent)
1099+
1100+
top_level_layout = qt.QFormLayout(self)
1101+
1102+
self.selector = qt.QComboBox()
1103+
self.forms = qt.QStackedWidget()
1104+
1105+
for cls in cls_list:
1106+
self.selector.addItem(cls.__name__)
1107+
widget = OpenLIFUAbstractDataclassDefinitionFormWidget(cls, parent, is_collapsible, collapsible_title)
1108+
# Override get_form_as_class
1109+
widget.get_form_as_class = types.MethodType(_get_form_as_segmentation_method, widget)
1110+
self.forms.addWidget(widget)
1111+
1112+
top_level_layout.addRow(qt.QLabel(f"{self.custom_abc_title} type"), self.selector)
1113+
top_level_layout.addRow(qt.QLabel(f"{self.custom_abc_title} options"), self.forms)
1114+
1115+
# Connect combo box to setting the widget. Assumes indices match
1116+
self.selector.currentIndexChanged.connect(self._on_index_changed)
1117+
1118+
# ---- Configure selector behavior ----
1119+
1120+
# Select UniformWater as the default
1121+
self.forms.setCurrentIndex(2)
1122+
1123+
# ---- Configure UniformTissue editor ----
1124+
1125+
uniformtissue_definition_form_widget = self.forms.widget(1)
1126+
1127+
# Disable editing the reference material
1128+
ref_material_line_edit = uniformtissue_definition_form_widget._field_widgets['ref_material']
1129+
ref_material_line_edit.setEnabled(False)
1130+
1131+
# ---- Configure UniformWater editor ----
1132+
1133+
uniformwater_definition_form_widget = self.forms.widget(2)
1134+
1135+
# Disable editing the reference material
1136+
ref_material_line_edit = uniformwater_definition_form_widget._field_widgets['ref_material']
1137+
ref_material_line_edit.setEnabled(False)
1138+
1139+
10641140
class OpenLIFUParameterConstraintsWidget(DictTableWidget):
10651141

10661142
class CreateParameterParameterConstraintDialog(qt.QDialog):

OpenLIFUProtocolConfig/Resources/UI/OpenLIFUProtocolConfig.ui

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,13 @@ OpenLIFUAbstractApodizationMethodDefinitionWidget</string>
274274
</widget>
275275
</item>
276276
<item>
277-
<widget class="QWidget" name="segmentationMethodDefinitionWidgetPlaceholder" native="true">
277+
<widget class="QWidget" name="abstractSegmentationMethodDefinitionWidgetPlaceholder" native="true">
278278
<layout class="QVBoxLayout" name="verticalLayout_13">
279279
<item>
280-
<widget class="QLabel" name="segmentationMethodDefinitionWidgetPlaceholderLabel">
280+
<widget class="QLabel" name="abstractSegmentationMethodDefinitionWidgetPlaceholderLabel">
281281
<property name="text">
282282
<string>Placeholder for an
283-
OpenLIFUSegmentationMethodDefinitionWidget</string>
283+
OpenLIFUAbstractSegmentationMethodDefinitionWidget</string>
284284
</property>
285285
</widget>
286286
</item>

0 commit comments

Comments
 (0)