Skip to content

Commit 84b14c7

Browse files
authored
Merge pull request #18599 from anntzer/wxrub
Simplify wx rubberband drawing.
2 parents 7ce2f67 + 7465670 commit 84b14c7

File tree

1 file changed

+29
-149
lines changed

1 file changed

+29
-149
lines changed

lib/matplotlib/backends/backend_wx.py

+29-149
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,8 @@ def __init__(self, parent, id, figure):
525525
# Create the drawing bitmap
526526
self.bitmap = wx.Bitmap(w, h)
527527
_log.debug("%s - __init__() - bitmap w:%d h:%d", type(self), w, h)
528-
# TODO: Add support for 'point' inspection and plot navigation.
529528
self._isDrawn = False
529+
self._rubberband_rect = None
530530

531531
self.Bind(wx.EVT_SIZE, self._onSize)
532532
self.Bind(wx.EVT_PAINT, self._onPaint)
@@ -625,20 +625,22 @@ def gui_repaint(self, drawDC=None, origin='WX'):
625625
_log.debug("%s - gui_repaint()", type(self))
626626
# The "if self" check avoids a "wrapped C/C++ object has been deleted"
627627
# RuntimeError if doing things after window is closed.
628-
if self and self.IsShownOnScreen():
629-
if not drawDC:
630-
# not called from OnPaint use a ClientDC
631-
drawDC = wx.ClientDC(self)
632-
633-
# following is for 'WX' backend on Windows
634-
# the bitmap can not be in use by another DC,
635-
# see GraphicsContextWx._cache
636-
if wx.Platform == '__WXMSW__' and origin == 'WX':
637-
img = self.bitmap.ConvertToImage()
638-
bmp = img.ConvertToBitmap()
639-
drawDC.DrawBitmap(bmp, 0, 0)
640-
else:
641-
drawDC.DrawBitmap(self.bitmap, 0, 0)
628+
if not (self and self.IsShownOnScreen()):
629+
return
630+
if not drawDC: # not called from OnPaint use a ClientDC
631+
drawDC = wx.ClientDC(self)
632+
# For 'WX' backend on Windows, the bitmap can not be in use by another
633+
# DC (see GraphicsContextWx._cache).
634+
bmp = (self.bitmap.ConvertToImage().ConvertToBitmap()
635+
if wx.Platform == '__WXMSW__' and origin == 'WX'
636+
else self.bitmap)
637+
drawDC.DrawBitmap(bmp, 0, 0)
638+
if self._rubberband_rect is not None:
639+
x0, y0, x1, y1 = self._rubberband_rect
640+
drawDC.DrawLineList(
641+
[(x0, y0, x1, y0), (x1, y0, x1, y1),
642+
(x0, y0, x0, y1), (x0, y1, x1, y1)],
643+
wx.Pen('BLACK', 1, wx.PENSTYLE_SHORT_DASH))
642644

643645
filetypes = {
644646
**FigureCanvasBase.filetypes,
@@ -1249,58 +1251,13 @@ def release_zoom(self, event):
12491251
self._zoomAxes = None
12501252

12511253
def draw_rubberband(self, event, x0, y0, x1, y1):
1252-
if self._retinaFix: # On Macs, use the following code
1253-
# wx.DCOverlay does not work properly on Retina displays.
1254-
rubberBandColor = '#C0C0FF'
1255-
if self._prevZoomRect:
1256-
self._prevZoomRect.pop(0).remove()
1257-
self.canvas.restore_region(self._savedRetinaImage)
1258-
X0, X1 = self._zoomStartX, event.xdata
1259-
Y0, Y1 = self._zoomStartY, event.ydata
1260-
lineX = (X0, X0, X1, X1, X0)
1261-
lineY = (Y0, Y1, Y1, Y0, Y0)
1262-
self._prevZoomRect = self._zoomAxes.plot(
1263-
lineX, lineY, '-', color=rubberBandColor)
1264-
self._zoomAxes.draw_artist(self._prevZoomRect[0])
1265-
self.canvas.blit(self._zoomAxes.bbox)
1266-
return
1267-
1268-
# Use an Overlay to draw a rubberband-like bounding box.
1269-
1270-
dc = wx.ClientDC(self.canvas)
1271-
odc = wx.DCOverlay(self._wxoverlay, dc)
1272-
odc.Clear()
1273-
1274-
# Mac's DC is already the same as a GCDC, and it causes
1275-
# problems with the overlay if we try to use an actual
1276-
# wx.GCDC so don't try it.
1277-
if 'wxMac' not in wx.PlatformInfo:
1278-
dc = wx.GCDC(dc)
1279-
12801254
height = self.canvas.figure.bbox.height
1281-
y1 = height - y1
1282-
y0 = height - y0
1283-
1284-
if y1 < y0:
1285-
y0, y1 = y1, y0
1286-
if x1 < x0:
1287-
x0, x1 = x1, x0
1288-
1289-
w = x1 - x0
1290-
h = y1 - y0
1291-
rect = wx.Rect(x0, y0, w, h)
1255+
self.canvas._rubberband_rect = (x0, height - y0, x1, height - y1)
1256+
self.canvas.Refresh()
12921257

1293-
rubberBandColor = '#C0C0FF' # or load from config?
1294-
1295-
# Set a pen for the border
1296-
color = wx.Colour(rubberBandColor)
1297-
dc.SetPen(wx.Pen(color, 1))
1298-
1299-
# use the same color, plus alpha for the brush
1300-
r, g, b, a = color.Get(True)
1301-
color.Set(r, g, b, 0x60)
1302-
dc.SetBrush(wx.Brush(color))
1303-
dc.DrawRectangle(rect)
1258+
def remove_rubberband(self):
1259+
self.canvas._rubberband_rect = None
1260+
self.canvas.Refresh()
13041261

13051262
def set_message(self, s):
13061263
if self._coordinates:
@@ -1448,91 +1405,14 @@ def set_cursor(self, cursor):
14481405
self._make_classic_style_pseudo_toolbar(), cursor)
14491406

14501407

1451-
if 'wxMac' not in wx.PlatformInfo:
1452-
# on most platforms, use overlay
1453-
class RubberbandWx(backend_tools.RubberbandBase):
1454-
def __init__(self, *args, **kwargs):
1455-
super().__init__(*args, **kwargs)
1456-
self._wxoverlay = None
1408+
class RubberbandWx(backend_tools.RubberbandBase):
1409+
def draw_rubberband(self, x0, y0, x1, y1):
1410+
NavigationToolbar2Wx.draw_rubberband(
1411+
self._make_classic_style_pseudo_toolbar(), None, x0, y0, x1, y1)
14571412

1458-
def draw_rubberband(self, x0, y0, x1, y1):
1459-
# Use an Overlay to draw a rubberband-like bounding box.
1460-
if self._wxoverlay is None:
1461-
self._wxoverlay = wx.Overlay()
1462-
dc = wx.ClientDC(self.canvas)
1463-
odc = wx.DCOverlay(self._wxoverlay, dc)
1464-
odc.Clear()
1465-
1466-
dc = wx.GCDC(dc)
1467-
1468-
height = self.canvas.figure.bbox.height
1469-
y1 = height - y1
1470-
y0 = height - y0
1471-
1472-
if y1 < y0:
1473-
y0, y1 = y1, y0
1474-
if x1 < x0:
1475-
x0, x1 = x1, x0
1476-
1477-
w = x1 - x0
1478-
h = y1 - y0
1479-
rect = wx.Rect(x0, y0, w, h)
1480-
1481-
rubberBandColor = '#C0C0FF' # or load from config?
1482-
1483-
# Set a pen for the border
1484-
color = wx.Colour(rubberBandColor)
1485-
dc.SetPen(wx.Pen(color, 1))
1486-
1487-
# use the same color, plus alpha for the brush
1488-
r, g, b, a = color.Get(True)
1489-
color.Set(r, g, b, 0x60)
1490-
dc.SetBrush(wx.Brush(color))
1491-
dc.DrawRectangle(rect)
1492-
1493-
def remove_rubberband(self):
1494-
if self._wxoverlay is None:
1495-
return
1496-
self._wxoverlay.Reset()
1497-
self._wxoverlay = None
1498-
1499-
else:
1500-
# on Mac OS retina displays DCOverlay does not work
1501-
# and dc.SetLogicalFunction does not have an effect on any display
1502-
# the workaround is to blit the full image for remove_rubberband
1503-
class RubberbandWx(backend_tools.RubberbandBase):
1504-
def __init__(self, *args, **kwargs):
1505-
super().__init__(*args, **kwargs)
1506-
self._rect = None
1507-
1508-
def draw_rubberband(self, x0, y0, x1, y1):
1509-
dc = wx.ClientDC(self.canvas)
1510-
# this would be required if the Canvas is a ScrolledWindow,
1511-
# which is not the case for now
1512-
# self.PrepareDC(dc)
1513-
1514-
# delete old rubberband
1515-
if self._rect:
1516-
self.remove_rubberband(dc)
1517-
1518-
# draw new rubberband
1519-
dc.SetPen(wx.Pen(wx.BLACK, 1, wx.SOLID))
1520-
dc.SetBrush(wx.TRANSPARENT_BRUSH)
1521-
self._rect = (x0, self.canvas._height-y0, x1-x0, -y1+y0)
1522-
dc.DrawRectangle(self._rect)
1523-
1524-
def remove_rubberband(self, dc=None):
1525-
if not self._rect:
1526-
return
1527-
if self.canvas.bitmap:
1528-
if dc is None:
1529-
dc = wx.ClientDC(self.canvas)
1530-
dc.DrawBitmap(self.canvas.bitmap, 0, 0)
1531-
# for testing the method on Windows, use this code instead:
1532-
# img = self.canvas.bitmap.ConvertToImage()
1533-
# bmp = img.ConvertToBitmap()
1534-
# dc.DrawBitmap(bmp, 0, 0)
1535-
self._rect = None
1413+
def remove_rubberband(self):
1414+
NavigationToolbar2Wx.remove_rubberband(
1415+
self._make_classic_style_pseudo_toolbar())
15361416

15371417

15381418
class _HelpDialog(wx.Dialog):

0 commit comments

Comments
 (0)