11
11
12
12
from contextlib import ExitStack
13
13
import copy
14
+ import enum
14
15
import itertools
15
16
from numbers import Integral , Number
16
17
@@ -150,6 +151,10 @@ def ignore(self, event):
150
151
# docstring inherited
151
152
return super ().ignore (event ) or self .canvas is None
152
153
154
+ def _set_cursor (self , cursor ):
155
+ """Update the canvas cursor."""
156
+ self .ax .get_figure (root = True ).canvas .set_cursor (cursor )
157
+
153
158
154
159
class Button (AxesWidget ):
155
160
"""
@@ -2645,7 +2650,7 @@ def _handles_artists(self):
2645
2650
else :
2646
2651
return ()
2647
2652
2648
- def _set_cursor (self , enabled ):
2653
+ def _set_span_cursor (self , * , enabled ):
2649
2654
"""Update the canvas cursor based on direction of the selector."""
2650
2655
if enabled :
2651
2656
cursor = (backend_tools .Cursors .RESIZE_HORIZONTAL
@@ -2654,7 +2659,7 @@ def _set_cursor(self, enabled):
2654
2659
else :
2655
2660
cursor = backend_tools .Cursors .POINTER
2656
2661
2657
- self .ax . get_figure ( root = True ). canvas . set_cursor (cursor )
2662
+ self ._set_cursor (cursor )
2658
2663
2659
2664
def connect_default_events (self ):
2660
2665
# docstring inherited
@@ -2664,7 +2669,7 @@ def connect_default_events(self):
2664
2669
2665
2670
def _press (self , event ):
2666
2671
"""Button press event handler."""
2667
- self ._set_cursor ( True )
2672
+ self ._set_span_cursor ( enabled = True )
2668
2673
if self ._interactive and self ._selection_artist .get_visible ():
2669
2674
self ._set_active_handle (event )
2670
2675
else :
@@ -2714,7 +2719,7 @@ def direction(self, direction):
2714
2719
2715
2720
def _release (self , event ):
2716
2721
"""Button release event handler."""
2717
- self ._set_cursor ( False )
2722
+ self ._set_span_cursor ( enabled = False )
2718
2723
2719
2724
if not self ._interactive :
2720
2725
self ._selection_artist .set_visible (False )
@@ -2756,7 +2761,7 @@ def _hover(self, event):
2756
2761
return
2757
2762
2758
2763
_ , e_dist = self ._edge_handles .closest (event .x , event .y )
2759
- self ._set_cursor ( e_dist <= self .grab_range )
2764
+ self ._set_span_cursor ( enabled = e_dist <= self .grab_range )
2760
2765
2761
2766
def _onmove (self , event ):
2762
2767
"""Motion notify event handler."""
@@ -3147,6 +3152,13 @@ def onselect(eclick: MouseEvent, erelease: MouseEvent)
3147
3152
"""
3148
3153
3149
3154
3155
+ class _RectangleSelectorAction (enum .Enum ):
3156
+ ROTATE = enum .auto ()
3157
+ MOVE = enum .auto ()
3158
+ RESIZE = enum .auto ()
3159
+ CREATE = enum .auto ()
3160
+
3161
+
3150
3162
@_docstring .Substitution (_RECTANGLESELECTOR_PARAMETERS_DOCSTRING .replace (
3151
3163
'__ARTIST_NAME__' , 'rectangle' ))
3152
3164
class RectangleSelector (_SelectorWidget ):
@@ -3280,10 +3292,23 @@ def _press(self, event):
3280
3292
self ._rotation_on_press = self ._rotation
3281
3293
self ._set_aspect_ratio_correction ()
3282
3294
3295
+ match self ._get_action ():
3296
+ case _RectangleSelectorAction .ROTATE :
3297
+ # TODO: set to a rotate cursor if possible?
3298
+ pass
3299
+ case _RectangleSelectorAction .MOVE :
3300
+ self ._set_cursor (backend_tools .cursors .MOVE )
3301
+ case _RectangleSelectorAction .RESIZE :
3302
+ # TODO: set to a resize cursor if possible?
3303
+ pass
3304
+ case _RectangleSelectorAction .CREATE :
3305
+ self ._set_cursor (backend_tools .cursors .SELECT_REGION )
3306
+
3283
3307
return False
3284
3308
3285
3309
def _release (self , event ):
3286
3310
"""Button release event handler."""
3311
+ self ._set_cursor (backend_tools .Cursors .POINTER )
3287
3312
if not self ._interactive :
3288
3313
self ._selection_artist .set_visible (False )
3289
3314
@@ -3327,9 +3352,20 @@ def _release(self, event):
3327
3352
self .update ()
3328
3353
self ._active_handle = None
3329
3354
self ._extents_on_press = None
3330
-
3331
3355
return False
3332
3356
3357
+ def _get_action (self ):
3358
+ state = self ._state
3359
+ if 'rotate' in state and self ._active_handle in self ._corner_order :
3360
+ return _RectangleSelectorAction .ROTATE
3361
+ elif self ._active_handle == 'C' :
3362
+ return _RectangleSelectorAction .MOVE
3363
+ elif self ._active_handle :
3364
+ return _RectangleSelectorAction .RESIZE
3365
+
3366
+ return _RectangleSelectorAction .CREATE
3367
+
3368
+
3333
3369
def _onmove (self , event ):
3334
3370
"""
3335
3371
Motion notify event handler.
@@ -3344,12 +3380,10 @@ def _onmove(self, event):
3344
3380
# The calculations are done for rotation at zero: we apply inverse
3345
3381
# transformation to events except when we rotate and move
3346
3382
state = self ._state
3347
- rotate = 'rotate' in state and self ._active_handle in self ._corner_order
3348
- move = self ._active_handle == 'C'
3349
- resize = self ._active_handle and not move
3383
+ action = self ._get_action ()
3350
3384
3351
3385
xdata , ydata = self ._get_data_coords (event )
3352
- if resize :
3386
+ if action == _RectangleSelectorAction . RESIZE :
3353
3387
inv_tr = self ._get_rotation_transform ().inverted ()
3354
3388
xdata , ydata = inv_tr .transform ([xdata , ydata ])
3355
3389
eventpress .xdata , eventpress .ydata = inv_tr .transform (
@@ -3369,7 +3403,7 @@ def _onmove(self, event):
3369
3403
3370
3404
x0 , x1 , y0 , y1 = self ._extents_on_press
3371
3405
# rotate an existing shape
3372
- if rotate :
3406
+ if action == _RectangleSelectorAction . ROTATE :
3373
3407
# calculate angle abc
3374
3408
a = (eventpress .xdata , eventpress .ydata )
3375
3409
b = self .center
@@ -3378,7 +3412,7 @@ def _onmove(self, event):
3378
3412
np .arctan2 (a [1 ]- b [1 ], a [0 ]- b [0 ]))
3379
3413
self .rotation = np .rad2deg (self ._rotation_on_press + angle )
3380
3414
3381
- elif resize :
3415
+ elif action == _RectangleSelectorAction . RESIZE :
3382
3416
size_on_press = [x1 - x0 , y1 - y0 ]
3383
3417
center = (x0 + size_on_press [0 ] / 2 , y0 + size_on_press [1 ] / 2 )
3384
3418
@@ -3429,7 +3463,7 @@ def _onmove(self, event):
3429
3463
sign = np .sign (xdata - x0 )
3430
3464
x1 = x0 + sign * abs (y1 - y0 ) * self ._aspect_ratio_correction
3431
3465
3432
- elif move :
3466
+ elif action == _RectangleSelectorAction . MOVE :
3433
3467
x0 , x1 , y0 , y1 = self ._extents_on_press
3434
3468
dx = xdata - eventpress .xdata
3435
3469
dy = ydata - eventpress .ydata
0 commit comments