Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7465670

Browse files
committed
Simplify wx rubberband drawing.
Like for qt/gtk, it's much easier to just draw the rectangle at gui_repaint time. AFAICT this now works on Wayland too.
1 parent f9d2918 commit 7465670

1 file changed

Lines changed: 29 additions & 149 deletions

File tree

lib/matplotlib/backends/backend_wx.py

Lines changed: 29 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,8 @@ def __init__(self, parent, id, figure):
528528
# Create the drawing bitmap
529529
self.bitmap = wx.Bitmap(w, h)
530530
_log.debug("%s - __init__() - bitmap w:%d h:%d", type(self), w, h)
531-
# TODO: Add support for 'point' inspection and plot navigation.
532531
self._isDrawn = False
532+
self._rubberband_rect = None
533533

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

646648
filetypes = {
647649
**FigureCanvasBase.filetypes,
@@ -1250,58 +1252,13 @@ def release_zoom(self, event):
12501252
self._zoomAxes = None
12511253

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

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

13061263
def set_message(self, s):
13071264
if self._coordinates:
@@ -1449,91 +1406,14 @@ def set_cursor(self, cursor):
14491406
self._make_classic_style_pseudo_toolbar(), cursor)
14501407

14511408

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

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

15381418

15391419
class _HelpDialog(wx.Dialog):

0 commit comments

Comments
 (0)