0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-13 11:11:49 +02:00

feat(roi): rois can be lock to be not moved by mouse

This commit is contained in:
2025-06-10 15:18:24 +02:00
committed by Jan Wyzula
parent f9044996f6
commit 46d7e3f517
4 changed files with 134 additions and 2 deletions

View File

@ -530,6 +530,26 @@ class BaseROI(RPCBase):
str: The current name of the ROI.
"""
@property
@rpc_call
def movable(self) -> "bool":
"""
Gets whether this ROI is movable.
Returns:
bool: True if the ROI can be moved, False otherwise.
"""
@movable.setter
@rpc_call
def movable(self) -> "bool":
"""
Gets whether this ROI is movable.
Returns:
bool: True if the ROI can be moved, False otherwise.
"""
@property
@rpc_call
def line_color(self) -> "str":
@ -639,6 +659,26 @@ class CircularROI(RPCBase):
str: The current name of the ROI.
"""
@property
@rpc_call
def movable(self) -> "bool":
"""
Gets whether this ROI is movable.
Returns:
bool: True if the ROI can be moved, False otherwise.
"""
@movable.setter
@rpc_call
def movable(self) -> "bool":
"""
Gets whether this ROI is movable.
Returns:
bool: True if the ROI can be moved, False otherwise.
"""
@property
@rpc_call
def line_color(self) -> "str":
@ -1494,6 +1534,7 @@ class Image(RPCBase):
line_width: "int | None" = 5,
pos: "tuple[float, float] | None" = (10, 10),
size: "tuple[float, float] | None" = (50, 50),
movable: "bool" = True,
**pg_kwargs,
) -> "RectangularROI | CircularROI":
"""
@ -1505,6 +1546,7 @@ class Image(RPCBase):
line_width(int): The line width of the ROI.
pos(tuple): The position of the ROI.
size(tuple): The size of the ROI.
movable(bool): Whether the ROI is movable.
**pg_kwargs: Additional arguments for the ROI.
Returns:
@ -2664,6 +2706,26 @@ class RectangularROI(RPCBase):
str: The current name of the ROI.
"""
@property
@rpc_call
def movable(self) -> "bool":
"""
Gets whether this ROI is movable.
Returns:
bool: True if the ROI can be moved, False otherwise.
"""
@movable.setter
@rpc_call
def movable(self) -> "bool":
"""
Gets whether this ROI is movable.
Returns:
bool: True if the ROI can be moved, False otherwise.
"""
@property
@rpc_call
def line_color(self) -> "str":

View File

@ -559,6 +559,7 @@ class ImageBase(PlotBase):
line_width: int | None = 5,
pos: tuple[float, float] | None = (10, 10),
size: tuple[float, float] | None = (50, 50),
movable: bool = True,
**pg_kwargs,
) -> RectangularROI | CircularROI:
"""
@ -570,6 +571,7 @@ class ImageBase(PlotBase):
line_width(int): The line width of the ROI.
pos(tuple): The position of the ROI.
size(tuple): The size of the ROI.
movable(bool): Whether the ROI is movable.
**pg_kwargs: Additional arguments for the ROI.
Returns:
@ -584,6 +586,7 @@ class ImageBase(PlotBase):
parent_image=self,
line_width=line_width,
label=name,
movable=movable,
**pg_kwargs,
)
elif kind == "circle":
@ -593,6 +596,7 @@ class ImageBase(PlotBase):
parent_image=self,
line_width=line_width,
label=name,
movable=movable,
**pg_kwargs,
)
else:

View File

@ -107,6 +107,8 @@ class BaseROI(BECConnector):
USER_ACCESS = [
"label",
"label.setter",
"movable",
"movable.setter",
"line_color",
"line_color.setter",
"line_width",
@ -164,11 +166,12 @@ class BaseROI(BECConnector):
self._line_color = line_color or "#ffffff"
self._line_width = line_width
self._description = True
self._movable = True # allow moving by default
self._movable = movable
self.setPen(mkPen(self._line_color, width=self._line_width))
# Reset Handles to avoid inherited handles from pyqtgraph
self.remove_scale_handles() # remove any existing handles from pyqtgraph.RectROI
if movable:
self.add_scale_handle() # add custom scale handles
def set_parent(self, parent: Image):
@ -189,6 +192,39 @@ class BaseROI(BECConnector):
"""
return self.parent_image
@property
def movable(self) -> bool:
"""
Gets whether this ROI is movable.
Returns:
bool: True if the ROI can be moved, False otherwise.
"""
return self._movable
@movable.setter
def movable(self, value: bool):
"""
Sets whether this ROI is movable.
If the new value is different from the current value, this method updates
the internal state and emits the penChanged signal.
Args:
value (bool): True to make the ROI movable, False to make it fixed.
"""
if value != self._movable:
self._movable = value
# All relevant properties from pyqtgraph to block movement
self.translatable = value
self.rotatable = value
self.resizable = value
self.removable = value
if value:
self.add_scale_handle() # add custom scale handles
else:
self.remove_scale_handles() # remove custom scale handles
@property
def label(self) -> str:
"""
@ -411,6 +447,7 @@ class RectangularROI(BaseROI, pg.RectROI):
label: str | None = None,
line_color: str | None = None,
line_width: int = 5,
movable: bool = True,
resize_handles: bool = True,
**extra_pg,
):
@ -441,6 +478,7 @@ class RectangularROI(BaseROI, pg.RectROI):
pos=pos,
size=size,
pen=pen,
movable=movable,
**extra_pg,
)
@ -588,6 +626,7 @@ class CircularROI(BaseROI, pg.CircleROI):
label: str | None = None,
line_color: str | None = None,
line_width: int = 5,
movable: bool = True,
**extra_pg,
):
"""
@ -619,6 +658,7 @@ class CircularROI(BaseROI, pg.CircleROI):
pos=pos,
size=size,
pen=pen,
movable=movable,
**extra_pg,
)
self.sigRegionChanged.connect(self._on_region_changed)

View File

@ -205,3 +205,29 @@ def test_roi_set_position(bec_image_widget_with_roi):
pos = roi.pos()
assert int(pos.x()) == 10
assert int(pos.y()) == 15
def test_roi_movable_property(bec_image_widget_with_roi, qtbot):
"""Verify BaseROI.movable toggles flags, handles, and emits a signal."""
_widget, roi, _ = bec_image_widget_with_roi
# defaults ROI is movable
assert roi.movable
assert roi.translatable and roi.rotatable and roi.resizable and roi.removable
assert len(roi.handles) > 0
# lock it
with qtbot.waitSignal(roi.movableChanged) as blocker:
roi.movable = False
assert blocker.args == [False]
assert not roi.movable
assert not (roi.translatable or roi.rotatable or roi.resizable or roi.removable)
assert len(roi.handles) == 0
# unlock again
with qtbot.waitSignal(roi.movableChanged) as blocker:
roi.movable = True
assert blocker.args == [True]
assert roi.movable
assert roi.translatable and roi.rotatable and roi.resizable and roi.removable
assert len(roi.handles) > 0