@@ -159,12 +159,14 @@ def __init__(self, figure):
159159
160160 self ._idle_draw_id = 0
161161 self ._lastCursor = None
162+ self ._rubberband_rect = None
162163
163164 self .connect ('scroll_event' , self .scroll_event )
164165 self .connect ('button_press_event' , self .button_press_event )
165166 self .connect ('button_release_event' , self .button_release_event )
166167 self .connect ('configure_event' , self .configure_event )
167168 self .connect ('draw' , self .on_draw_event )
169+ self .connect ('draw' , self ._post_draw )
168170 self .connect ('key_press_event' , self .key_press_event )
169171 self .connect ('key_release_event' , self .key_release_event )
170172 self .connect ('motion_notify_event' , self .motion_notify_event )
@@ -286,6 +288,40 @@ def configure_event(self, widget, event):
286288 self .figure .set_size_inches (w / dpi , h / dpi , forward = False )
287289 return False # finish event propagation?
288290
291+ def _draw_rubberband (self , rect ):
292+ self ._rubberband_rect = rect
293+ # TODO: Only update the rubberband area.
294+ self .queue_draw ()
295+
296+ def _post_draw (self , widget , ctx ):
297+ if self ._rubberband_rect is None :
298+ return
299+
300+ x0 , y0 , w , h = self ._rubberband_rect
301+ x1 = x0 + w
302+ y1 = y0 + h
303+
304+ # Draw the lines from x0, y0 towards x1, y1 so that the
305+ # dashes don't "jump" when moving the zoom box.
306+ ctx .move_to (x0 , y0 )
307+ ctx .line_to (x0 , y1 )
308+ ctx .move_to (x0 , y0 )
309+ ctx .line_to (x1 , y0 )
310+ ctx .move_to (x0 , y1 )
311+ ctx .line_to (x1 , y1 )
312+ ctx .move_to (x1 , y0 )
313+ ctx .line_to (x1 , y1 )
314+
315+ ctx .set_antialias (1 )
316+ ctx .set_line_width (1 )
317+ ctx .set_dash ((3 , 3 ), 0 )
318+ ctx .set_source_rgb (0 , 0 , 0 )
319+ ctx .stroke_preserve ()
320+
321+ ctx .set_dash ((3 , 3 ), 3 )
322+ ctx .set_source_rgb (1 , 1 , 1 )
323+ ctx .stroke ()
324+
289325 def on_draw_event (self , widget , ctx ):
290326 # to be overwritten by GTK3Agg or GTK3Cairo
291327 pass
@@ -507,26 +543,14 @@ def set_cursor(self, cursor):
507543 Gtk .main_iteration ()
508544
509545 def draw_rubberband (self , event , x0 , y0 , x1 , y1 ):
510- # adapted from
511- # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/189744
512- ctx = self .canvas .get_property ("window" ).cairo_create ()
513-
514- # todo: instead of redrawing the entire figure, copy the part of
515- # the figure that was covered by the previous rubberband rectangle
516- self .canvas .draw ()
517-
518546 height = self .canvas .figure .bbox .height
519547 y1 = height - y1
520548 y0 = height - y0
521- w = abs (x1 - x0 )
522- h = abs (y1 - y0 )
523- rect = [int (val ) for val in (min (x0 , x1 ), min (y0 , y1 ), w , h )]
549+ rect = [int (val ) for val in (x0 , y0 , x1 - x0 , y1 - y0 )]
550+ self .canvas ._draw_rubberband (rect )
524551
525- ctx .new_path ()
526- ctx .set_line_width (0.5 )
527- ctx .rectangle (rect [0 ], rect [1 ], rect [2 ], rect [3 ])
528- ctx .set_source_rgb (0 , 0 , 0 )
529- ctx .stroke ()
552+ def remove_rubberband (self ):
553+ self .canvas ._draw_rubberband (None )
530554
531555 def _update_buttons_checked (self ):
532556 for name , active in [("Pan" , "PAN" ), ("Zoom" , "ZOOM" )]:
@@ -721,6 +745,10 @@ def draw_rubberband(self, x0, y0, x1, y1):
721745 NavigationToolbar2GTK3 .draw_rubberband (
722746 self ._make_classic_style_pseudo_toolbar (), None , x0 , y0 , x1 , y1 )
723747
748+ def remove_rubberband (self ):
749+ NavigationToolbar2GTK3 .remove_rubberband (
750+ self ._make_classic_style_pseudo_toolbar ())
751+
724752
725753class SaveFigureGTK3 (backend_tools .SaveFigureBase ):
726754 def trigger (self , * args , ** kwargs ):
0 commit comments