1717from plotpy .plot .base import BasePlot
1818from plotpy .plot .plotwidget import PlotWindow
1919from plotpy .tests .data import gen_image4
20+ from plotpy .tests .items .test_transform import make_items
2021from plotpy .tests .unit .utils import (
2122 create_window ,
2223 drag_mouse ,
2728# guitest: show
2829
2930
31+ def _assert_images_angle (
32+ images : list [TrImageItem ], ref_angle : float , target_angle : float | None = None
33+ ) -> None :
34+ angle = images [0 ].param .pos_angle
35+ assert angle > ref_angle
36+ if target_angle is not None :
37+ assert np .isclose (angle , target_angle , 0.5 )
38+ for img in images :
39+ assert np .isclose (angle , img .param .pos_angle )
40+
41+
42+ def _assert_images_pos (images : list [TrImageItem ], x0 : float , y0 : float ) -> None :
43+ x = images [0 ].param .pos_x0
44+ y = images [0 ].param .pos_y0
45+ assert x > x0
46+ assert y > y0
47+ for img in images :
48+ assert img .param .pos_angle == 0
49+ assert np .isclose (x , img .param .pos_x0 )
50+ assert np .isclose (y , img .param .pos_y0 )
51+
52+
3053def _get_xy_coords (tr_img : TrImageItem ) -> tuple [float , float , float , float ]:
3154 x1 , y1 , x2 , y2 = tr_img .boundingRect ().getCoords ()
3255 assert isinstance (x1 , float )
@@ -39,6 +62,7 @@ def _get_xy_coords(tr_img: TrImageItem) -> tuple[float, float, float, float]:
3962def _setup_plot () -> tuple [PlotWindow , SelectTool , BasePlot , TrImageItem ]:
4063 tr_img = make .trimage (gen_image4 (100 , 100 ), x0 = 100 , y0 = 100 )
4164 win , tool = create_window (SelectTool , IImageItemType , None , [tr_img ])
65+ win .show ()
4266
4367 assert isinstance (tool , SelectTool )
4468
@@ -164,6 +188,7 @@ def test_select_all_items():
164188 make .legend (),
165189 ]
166190 win , tool = create_window (SelectTool , items = items )
191+ win .show ()
167192
168193 # The item list should contain none selectable items like the plot grid
169194 selectable_items = [item for item in items if item .can_select ()]
@@ -185,10 +210,10 @@ def test_rotate_with_mouse():
185210 assert init_angle == 0
186211 assert plot .get_selected_items () == [tr_img ]
187212
188- drag_mouse (win , qapp , np .linspace (0 , 1 , 100 ), np .linspace (0 , 1 , 100 ))
213+ drag_mouse (win , qapp , np .linspace (0 , 0.5 , 100 ), np .linspace (0 , 0.0 , 100 ))
189214
190215 assert plot .get_selected_items () == [tr_img ]
191- assert 179 < abs (tr_img .param .pos_angle ) < 181 # type: ignore
216+ assert np . isclose ( abs (tr_img .param .pos_angle ), 45 , 0.5 ) # type: ignore
192217
193218 exec_dialog (win )
194219
@@ -212,6 +237,7 @@ def test_rectangular_selection():
212237 for item in items
213238 ]
214239 win , tool = create_window (RectangularSelectionTool , items = items )
240+ win .show ()
215241 plot = win .manager .get_plot ()
216242
217243 drag_mouse (
@@ -228,10 +254,97 @@ def test_rectangular_selection():
228254 assert item in selected_items
229255
230256
257+ @pytest .mark .parametrize (
258+ "mouse_path, rotation" ,
259+ [
260+ ((np .linspace (0.0 , 0.5 , 100 ), np .zeros (100 )), True ),
261+ ((np .linspace (0.5 , 0.8 , 100 ), np .linspace (0.5 , 0.8 , 100 )), False ),
262+ ],
263+ )
264+ def test_multi_rotate_move_with_mouse (
265+ mouse_path : tuple [np .ndarray , np .ndarray ], rotation : bool
266+ ):
267+ n = 100
268+ x0 = n
269+ y0 = 0
270+
271+ with qt_app_context () as qapp :
272+ # All images are superimposed so that it is easy to select the corners for
273+ # rotations
274+ images = [make .trimage (gen_image4 (n , n ), x0 = x0 , y0 = y0 ) for i in range (3 )]
275+ initial_angle = 0
276+
277+ win , tool = create_window (
278+ SelectTool , active_item_type = IImageItemType , items = images
279+ )
280+ win .show ()
281+ keyboard_event (
282+ win , qapp , QC .Qt .Key .Key_A , mod = QC .Qt .KeyboardModifier .ControlModifier
283+ )
284+ drag_mouse (win , qapp , mouse_path [0 ], mouse_path [1 ])
285+
286+ if rotation :
287+ _assert_images_angle (images , ref_angle = initial_angle )
288+ else :
289+ _assert_images_pos (images , x0 , y0 )
290+
291+ exec_dialog (win )
292+
293+
294+ @pytest .mark .parametrize (
295+ "keymod, rotation" ,
296+ [
297+ (QC .Qt .KeyboardModifier .ControlModifier , False ),
298+ (QC .Qt .KeyboardModifier .ShiftModifier , True ),
299+ (
300+ QC .Qt .KeyboardModifier .ControlModifier
301+ | QC .Qt .KeyboardModifier .ShiftModifier ,
302+ True ,
303+ ),
304+ ],
305+ )
306+ def test_multi_rotate_move_with_keyboard (
307+ keymod : QC .Qt .KeyboardModifier , rotation : bool
308+ ):
309+ n = 100
310+ x0 = n
311+ y0 = 0
312+
313+ with qt_app_context () as qapp :
314+ # All images are superimposed so that it is easy to select the corners for
315+ # rotations
316+ images = [make .trimage (gen_image4 (n , n ), x0 = x0 , y0 = y0 ) for i in range (3 )]
317+
318+ win , tool = create_window (
319+ SelectTool , active_item_type = IImageItemType , items = images
320+ )
321+ win .show ()
322+ keyboard_event (
323+ win , qapp , QC .Qt .Key .Key_A , mod = QC .Qt .KeyboardModifier .ControlModifier
324+ )
325+ for _ in range (10 ):
326+ # Should rotate/move left depending on modifier
327+ keyboard_event (win , qapp , QC .Qt .Key .Key_Right , mod = keymod )
328+ # Should never rotate
329+ keyboard_event (win , qapp , QC .Qt .Key .Key_Down , mod = keymod )
330+
331+ if rotation :
332+ _assert_images_angle (images , ref_angle = 0 )
333+ else :
334+ _assert_images_pos (images , x0 , y0 )
335+
336+ exec_dialog (win )
337+
338+
231339if __name__ == "__main__" :
232340 test_move_with_mouse ()
233341 test_move_with_arrows (QC .Qt .KeyboardModifier .NoModifier )
234342 test_rotate_with_arrow (QC .Qt .KeyboardModifier .ShiftModifier )
235343 test_select_all_items ()
236344 test_rotate_with_mouse ()
237345 test_rectangular_selection ()
346+ test_multi_rotate_move_with_mouse ((np .linspace (0.0 , 0.5 , 100 ), np .zeros (100 )), True )
347+ test_multi_rotate_move_with_mouse ((np .linspace (0.0 , 0.5 , 100 ), np .zeros (100 )), True )
348+ test_multi_rotate_move_with_keyboard (
349+ QC .Qt .KeyboardModifier .ShiftModifier , rotation = True
350+ )
0 commit comments