1- from typing import Protocol
1+ from typing import Callable , Protocol
22
33import numpy as np
44import pytest
55import qtpy .QtCore as QC
6+ import qtpy .QtWidgets as QW
67from guidata .qthelpers import exec_dialog , qt_app_context
78from qwt import QwtPlotItem
9+ from typing_extensions import TypeVar
810
911from plotpy .builder import make
1012from plotpy .interfaces .items import (
1315 IItemType ,
1416 IShapeItemType ,
1517)
18+ from plotpy .items .image .base import BaseImageItem
1619from plotpy .items .image .transform import TrImageItem
1720from plotpy .plot .base import BasePlot
1821from plotpy .plot .plotwidget import PlotWindow
2225 create_window ,
2326 drag_mouse ,
2427 keyboard_event ,
28+ undo_redo ,
2529)
2630from plotpy .tools import RectangularSelectionTool , SelectTool
2731
2832# guitest: show
2933
34+ BaseImageItemT = TypeVar ("BaseImageItemT" , bound = BaseImageItem )
35+
3036
3137def _assert_images_angle (
3238 images : list [TrImageItem ], ref_angle : float , target_angle : float | None = None
@@ -50,7 +56,7 @@ def _assert_images_pos(images: list[TrImageItem], x0: float, y0: float) -> None:
5056 assert np .isclose (y , img .param .pos_y0 )
5157
5258
53- def _get_xy_coords (tr_img : TrImageItem ) -> tuple [float , float , float , float ]:
59+ def _get_xy_coords (tr_img : BaseImageItem ) -> tuple [float , float , float , float ]:
5460 x1 , y1 , x2 , y2 = tr_img .boundingRect ().getCoords ()
5561 assert isinstance (x1 , float )
5662 assert isinstance (y1 , float )
@@ -59,37 +65,56 @@ def _get_xy_coords(tr_img: TrImageItem) -> tuple[float, float, float, float]:
5965 return x1 , y1 , x2 , y2
6066
6167
62- def _setup_plot () -> tuple [PlotWindow , SelectTool , BasePlot , TrImageItem ]:
63- tr_img = make .trimage (gen_image4 (100 , 100 ), x0 = 100 , y0 = 100 )
64- win , tool = create_window (SelectTool , IImageItemType , None , [tr_img ])
68+ def _setup_plot (
69+ img_item : BaseImageItem | None = None ,
70+ ) -> tuple [PlotWindow , SelectTool , BasePlot , BaseImageItem ]:
71+ if img_item is None :
72+ img_item = make .trimage (gen_image4 (100 , 100 ), x0 = 100 , y0 = 100 )
73+ win , tool = create_window (SelectTool , IImageItemType , None , [img_item ])
6574 win .show ()
6675
6776 assert isinstance (tool , SelectTool )
6877
6978 plot = win .manager .get_plot ()
70- assert plot .get_selected_items () == [tr_img ]
79+ assert plot .get_selected_items () == [img_item ]
7180
72- return win , tool , plot , tr_img
81+ return win , tool , plot , img_item
7382
7483
75- def test_move_with_mouse ():
84+ @pytest .mark .parametrize (
85+ "img_item_builder" ,
86+ [
87+ lambda : make .trimage (gen_image4 (100 , 100 ), x0 = 100 , y0 = 100 ),
88+ lambda : make .image (
89+ gen_image4 (100 , 100 ),
90+ center_on = (100 , 100 ),
91+ pixel_size = 1 ,
92+ lock_position = False ,
93+ ),
94+ ],
95+ )
96+ def test_move_with_mouse (img_item_builder : Callable [[], BaseImageItem ] | None ):
7697 """Test the select tool."""
7798
7899 with qt_app_context (exec_loop = False ) as qapp :
79- win , tool , plot , tr_img = _setup_plot ()
80- x1 , y1 , * _ = _get_xy_coords ( tr_img )
81- initial_angle = tr_img . param . pos_angle # type: ignore
100+ img_item = None if img_item_builder is None else img_item_builder ()
101+ win , tool , plot , img_item = _setup_plot ( img_item )
102+ x1 , y1 , * _ = _get_xy_coords ( img_item )
82103
83- assert initial_angle == 0
84- assert plot .get_selected_items () == [tr_img ]
104+ if img_item .can_rotate ():
105+ initial_angle = img_item .param .pos_angle # type: ignore
106+ assert initial_angle == 0
107+ assert plot .get_selected_items () == [img_item ]
85108
86109 drag_mouse (win , qapp , np .array ([0.5 , 0.6 , 0.7 ]), np .array ([0.5 , 0.6 , 0.7 ]))
87110
88- assert plot .get_selected_items () == [tr_img ]
89- x2 , y2 , * _ = _get_xy_coords (tr_img )
111+ assert plot .get_selected_items () == [img_item ]
112+ x2 , y2 , * _ = _get_xy_coords (img_item )
90113 assert x2 > x1 and y2 > y1
91- assert tr_img .param .pos_angle == initial_angle # type: ignore
114+ if img_item .can_rotate ():
115+ assert img_item .param .pos_angle == initial_angle # type: ignore
92116
117+ undo_redo (qapp , win )
93118 exec_dialog (win )
94119
95120
@@ -133,6 +158,8 @@ def test_move_with_arrows(
133158 assert tr_img .param .pos_angle == initial_angle # type: ignore
134159
135160 keyboard_event (win , qapp , QC .Qt .Key .Key_Enter )
161+
162+ undo_redo (qapp , win )
136163 exec_dialog (win )
137164
138165
@@ -174,6 +201,7 @@ def test_rotate_with_arrow(
174201 )
175202 assert np .isclose (tr_img .param .pos_angle , initial_angle ) # type: ignore
176203
204+ undo_redo (qapp , win )
177205 exec_dialog (win )
178206
179207
@@ -215,6 +243,7 @@ def test_rotate_with_mouse():
215243 assert plot .get_selected_items () == [tr_img ]
216244 assert np .isclose (abs (tr_img .param .pos_angle ), 45 , 0.5 ) # type: ignore
217245
246+ undo_redo (qapp , win )
218247 exec_dialog (win )
219248
220249
@@ -238,7 +267,6 @@ def test_rectangular_selection():
238267 ]
239268 win , tool = create_window (RectangularSelectionTool , items = items )
240269 win .show ()
241- plot = win .manager .get_plot ()
242270
243271 drag_mouse (
244272 win ,
@@ -253,6 +281,8 @@ def test_rectangular_selection():
253281 if selectable :
254282 assert item in selected_items
255283
284+ exec_dialog (win )
285+
256286
257287@pytest .mark .parametrize (
258288 "mouse_path, rotation" ,
@@ -288,6 +318,7 @@ def test_multi_rotate_move_with_mouse(
288318 else :
289319 _assert_images_pos (images , x0 , y0 )
290320
321+ undo_redo (qapp , win )
291322 exec_dialog (win )
292323
293324
@@ -333,11 +364,12 @@ def test_multi_rotate_move_with_keyboard(
333364 else :
334365 _assert_images_pos (images , x0 , y0 )
335366
367+ undo_redo (qapp , win )
336368 exec_dialog (win )
337369
338370
339371if __name__ == "__main__" :
340- test_move_with_mouse ()
372+ test_move_with_mouse (None )
341373 test_move_with_arrows (QC .Qt .KeyboardModifier .NoModifier )
342374 test_rotate_with_arrow (QC .Qt .KeyboardModifier .ShiftModifier )
343375 test_select_all_items ()
0 commit comments