@@ -2189,7 +2189,8 @@ def __init__(self, ax, onselect, drawtype='box',
2189
2189
minspanx = 0 , minspany = 0 , useblit = False ,
2190
2190
lineprops = None , rectprops = None , spancoords = 'data' ,
2191
2191
button = None , maxdist = 10 , marker_props = None ,
2192
- interactive = False , state_modifier_keys = None ):
2192
+ interactive = False , state_modifier_keys = None ,
2193
+ drag_from_anywhere = False ):
2193
2194
r"""
2194
2195
Parameters
2195
2196
----------
@@ -2261,13 +2262,18 @@ def onselect(eclick: MouseEvent, erelease: MouseEvent)
2261
2262
default: "ctrl".
2262
2263
2263
2264
"square" and "center" can be combined.
2265
+
2266
+ drag_from_anywhere : bool, optional
2267
+ If `True`, the widget can be moved by clicking anywhere within
2268
+ its bounds.
2264
2269
"""
2265
2270
super ().__init__ (ax , onselect , useblit = useblit , button = button ,
2266
2271
state_modifier_keys = state_modifier_keys )
2267
2272
2268
2273
self .to_draw = None
2269
2274
self .visible = True
2270
2275
self .interactive = interactive
2276
+ self .drag_from_anywhere = drag_from_anywhere
2271
2277
2272
2278
if drawtype == 'none' : # draw a line but make it invisible
2273
2279
drawtype = 'line'
@@ -2407,8 +2413,9 @@ def _onmove(self, event):
2407
2413
y1 = event .ydata
2408
2414
2409
2415
# move existing shape
2410
- elif (('move' in self .state or self .active_handle == 'C' )
2411
- and self ._extents_on_press is not None ):
2416
+ elif (('move' in self .state or self .active_handle == 'C' or
2417
+ (self .drag_from_anywhere and self ._contains (event ))) and
2418
+ self ._extents_on_press is not None ):
2412
2419
x0 , x1 , y0 , y1 = self ._extents_on_press
2413
2420
dx = event .xdata - self .eventpress .xdata
2414
2421
dy = event .ydata - self .eventpress .ydata
@@ -2536,19 +2543,28 @@ def _set_active_handle(self, event):
2536
2543
e_idx , e_dist = self ._edge_handles .closest (event .x , event .y )
2537
2544
m_idx , m_dist = self ._center_handle .closest (event .x , event .y )
2538
2545
2546
+ contains = self ._contains (event )
2539
2547
if 'move' in self .state :
2540
2548
self .active_handle = 'C'
2541
2549
self ._extents_on_press = self .extents
2542
-
2543
2550
# Set active handle as closest handle, if mouse click is close enough.
2544
2551
elif m_dist < self .maxdist * 2 :
2552
+ # Prioritise center handle over other handles
2545
2553
self .active_handle = 'C'
2546
- elif c_dist > self .maxdist and e_dist > self .maxdist :
2547
- self .active_handle = None
2548
- return
2554
+ elif (c_dist > self .maxdist and e_dist > self .maxdist ):
2555
+ # Not close to any handles
2556
+ if self .drag_from_anywhere and contains :
2557
+ # Check if we've clicked inside the region
2558
+ self .active_handle = 'C'
2559
+ self ._extents_on_press = self .extents
2560
+ else :
2561
+ self .active_handle = None
2562
+ return
2549
2563
elif c_dist < e_dist :
2564
+ # Closest to a corner handle
2550
2565
self .active_handle = self ._corner_order [c_idx ]
2551
2566
else :
2567
+ # Closest to an edge handle
2552
2568
self .active_handle = self ._edge_order [e_idx ]
2553
2569
2554
2570
# Save coordinates of rectangle at the start of handle movement.
@@ -2560,6 +2576,10 @@ def _set_active_handle(self, event):
2560
2576
y0 , y1 = y1 , event .ydata
2561
2577
self ._extents_on_press = x0 , x1 , y0 , y1
2562
2578
2579
+ def _contains (self , event ):
2580
+ """Return True if event is within the patch."""
2581
+ return self .to_draw .contains (event , radius = 0 )[0 ]
2582
+
2563
2583
@property
2564
2584
def geometry (self ):
2565
2585
"""
0 commit comments