Revision: 4185
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4185&view=rev
Author: mdboom
Date: 2007-11-09 08:35:15 -0800 (Fri, 09 Nov 2007)
Log Message:
-----------
Get wx backend working with wxGraphicsContext drawing.
Modified Paths:
--------------
branches/transforms/lib/matplotlib/backend_bases.py
branches/transforms/lib/matplotlib/backends/backend_wx.py
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py 2007-11-09 16:33:58 UTC
(rev 4184)
+++ branches/transforms/lib/matplotlib/backend_bases.py 2007-11-09 16:35:15 UTC
(rev 4185)
@@ -67,8 +67,6 @@
override this method in order to draw the marker only once and
reuse it multiple times.
"""
- ctx = gc.ctx
- ctx.new_path()
tpath = trans.transform_path(path)
for x, y in tpath.vertices:
self.draw_path(gc, marker_path,
Modified: branches/transforms/lib/matplotlib/backends/backend_wx.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-11-09
16:33:58 UTC (rev 4184)
+++ branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-11-09
16:35:15 UTC (rev 4185)
@@ -94,7 +94,7 @@
cvs_id = '$Id$'
-import sys, os, os.path, math, StringIO
+import sys, os, os.path, math, StringIO, weakref
# Debugging settings here...
# Debug level set here. If the debug level is less than 5, information
@@ -154,7 +154,9 @@
from matplotlib.artist import Artist
from matplotlib.cbook import exception_to_str
from matplotlib.figure import Figure
+from matplotlib.path import Path
from matplotlib.text import _process_text_args, Text
+from matplotlib.transforms import Affine2D
from matplotlib.widgets import SubplotTool
from matplotlib import rcParams
@@ -261,10 +263,14 @@
#return 1, 1
if ismath: s = self.strip_math(s)
- if self.gc is None: gc = self.new_gc()
+ if self.gc is None:
+ gc = self.new_gc()
+ else:
+ gc = self.gc
+ gfx_ctx = gc.gfx_ctx
font = self.get_wx_font(s, prop)
- self.gc.SetFont(font)
- w, h, descent, leading = self.gc.GetFullTextExtent(s)
+ gfx_ctx.SetFont(font, wx.BLACK)
+ w, h, descent, leading = gfx_ctx.GetFullTextExtent(s)
return w, h, descent
@@ -272,97 +278,49 @@
'return the canvas width and height in display coords'
return self.width, self.height
-
- def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2,
rotation):
- """
- Draw an arc centered at x,y with width and height and angles
- from 0.0 to 360.0.
- If rgbFace is present, fill the figure in this colour, otherwise
- it is not filled.
- """
+ def handle_clip_rectangle(self, gc):
+ new_bounds = gc.get_clip_rectangle()
+ if new_bounds is not None:
+ new_bounds = new_bounds.bounds
+ gfx_ctx = gc.gfx_ctx
+ if gfx_ctx._lastcliprect != new_bounds:
+ gfx_ctx._lastcliprect = new_bounds
+ if new_bounds is None:
+ gfx_ctx.ResetClip()
+ else:
+ gfx_ctx.Clip(*new_bounds)
+
+ [EMAIL PROTECTED]
+ def convert_path(gfx_ctx, tpath):
+ wxpath = gfx_ctx.CreatePath()
+ for points, code in tpath.iter_segments():
+ if code == Path.MOVETO:
+ wxpath.MoveToPoint(*points)
+ elif code == Path.LINETO:
+ wxpath.AddLineToPoint(*points)
+ elif code == Path.CURVE3:
+ wxpath.AddQuadCurveToPoint(*points)
+ elif code == Path.CURVE4:
+ wxpath.AddCurveToPoint(*points)
+ elif code == Path.CLOSEPOLY:
+ wxpath.CloseSubpath()
+ return wxpath
+ convert_path = staticmethod(convert_path)
+
+ def draw_path(self, gc, path, transform, rgbFace=None):
gc.select()
- assert gc.Ok(), "wxMemoryDC not OK to use"
- # wxPython requires upper left corner of bounding rectange for ellipse
- # Theoretically you don't need the int() below, but it seems to make
- # rounding of arc centre point more accurate in screen co-ordinates
- ulX = x - int(width/2)
- ulY = self.height - int(y + (height/2))
+ self.handle_clip_rectangle(gc)
+ gfx_ctx = gc.gfx_ctx
+ transform = transform + Affine2D().scale(1.0, -1.0).translate(0.0,
self.height)
+ tpath = transform.transform_path(path)
+ wxpath = self.convert_path(gfx_ctx, tpath)
if rgbFace is not None:
- r,g,b = self._to_wx_rgb(rgbFace)
- new_brush =wx.Brush(wx.Colour(r,g,b), wx.SOLID)
- gc.SetBrush(new_brush)
+ gfx_ctx.SetBrush(wx.Brush(gc.get_wxcolour(rgbFace)))
+ gfx_ctx.DrawPath(wxpath)
else:
- gc.SetBrush(wx.TRANSPARENT_BRUSH)
- gc.DrawEllipticArc(int(ulX), int(ulY), int(width)+1, int(height)+1,
- int(angle1), int(angle2))
+ gfx_ctx.StrokePath(wxpath)
gc.unselect()
- def draw_line(self, gc, x1, y1, x2, y2):
- """
- Draw a single line from x1,y1 to x2,y2
- """
- DEBUG_MSG("draw_line()", 1, self)
- gc.select()
- gc.DrawLine(int(x1), self.height - int(y1),
- int(x2), self.height - int(y2))
- gc.unselect()
-
- def draw_lines(self, gc, x, y):
- """
- x and y are equal length arrays, draw lines connecting each
- point in x, y
- """
- gc.select()
- assert gc.Ok(), "wxMemoryDC not OK to use"
- assert len(x) == len(y), "draw_lines() x and y must be of equal length"
- gc.DrawLines([wx.Point(int(x[i]), self.height - int(y[i])) for i in
range(len(x))])
- gc.unselect()
-
- def draw_polygon(self, gc, rgbFace, points):
- """
- Draw a polygon. points is a len vertices tuple, each element
- giving the x,y coords a vertex
- """
- gc.select()
- assert gc.Ok(), "wxMemoryDC not OK to use"
- points = [(int(x), self.height - int(y)) for x,y in points]
- if rgbFace is not None:
- r,g,b = self._to_wx_rgb(rgbFace)
- new_brush =wx.Brush(wx.Colour(r,g,b), wx.SOLID)
- gc.SetBrush(new_brush)
- else:
- gc.SetBrush(wx.TRANSPARENT_BRUSH)
- gc.DrawPolygon(points)
- gc.unselect()
-
- def draw_rectangle(self, gc, rgbFace, x, y, width, height):
- """
- Draw a rectangle at lower left x,y with width and height
- If filled=True, fill the rectangle with the gc foreground
- gc is a GraphicsContext instance
- """
- # wxPython uses rectangle from TOP left!
- gc.select()
- assert gc.Ok(), "wxMemoryDC not OK to use"
- if rgbFace is not None:
- r,g,b = self._to_wx_rgb(rgbFace)
- new_brush =wx.Brush(wx.Colour(r,g,b), wx.SOLID)
- gc.SetBrush(new_brush)
- else:
- gc.SetBrush(wx.TRANSPARENT_BRUSH)
- gc.DrawRectangle(int(x), self.height - int(height + y),
- int(math.ceil(width)), int(math.ceil(height)))
- gc.unselect()
-
- def draw_point(self, gc, x, y):
- """
- Draw a single point at x,y
- """
- gc.select()
- assert gc.Ok(), "wxMemoryDC not OK to use"
- gc.DrawPoint(int(x), self.height - int(y))
- gc.unselect()
-
def draw_text(self, gc, x, y, s, prop, angle, ismath):
"""
Render the matplotlib.text.Text instance
@@ -371,21 +329,23 @@
if ismath: s = self.strip_math(s)
DEBUG_MSG("draw_text()", 1, self)
gc.select()
-
+ self.handle_clip_rectangle(gc)
+ gfx_ctx = gc.gfx_ctx
+
font = self.get_wx_font(s, prop)
- gc.SetFont(font)
- assert gc.Ok(), "wxMemoryDC not OK to use"
+ color = gc.get_wxcolour(gc.get_rgb())
+ gfx_ctx.SetFont(font, color)
w, h, d = self.get_text_width_height_descent(s, prop, ismath)
x = int(x)
y = int(y-h)
- if angle!=0:
- try: gc.DrawRotatedText(s, x, y, angle)
- except:
- verbose.print_error(exception_to_str('WX rotated text failed'))
+ if angle == 0.0:
+ gfx_ctx.DrawText(s, x, y)
else:
- gc.DrawText(s, x, y)
+ angle = angle * (math.pi / 180.0)
+ gfx_ctx.DrawRotatedText(s, x, y, angle)
+
gc.unselect()
def new_gc(self):
@@ -395,7 +355,6 @@
DEBUG_MSG('new_gc()', 2, self)
self.gc = GraphicsContextWx(self.bitmap, self)
self.gc.select()
- assert self.gc.Ok(), "wxMemoryDC not OK to use"
self.gc.unselect()
return self.gc
@@ -446,14 +405,7 @@
return font
- def _to_wx_rgb(self, rgb):
- """Takes a colour value and returns a tuple (r,g,b) suitable
- for instantiating a wx.Colour."""
- r, g, b = rgb
- return (int(r * 255), int(g * 255), int(b * 255))
-
-
def points_to_pixels(self, points):
"""
convert point measures to pixes using dpi and the pixels per
@@ -461,15 +413,15 @@
"""
return points*(PIXELS_PER_INCH/72.0*self.dpi/72.0)
-class GraphicsContextWx(GraphicsContextBase, wx.MemoryDC):
+class GraphicsContextWx(GraphicsContextBase):
"""
The graphics context provides the color, line styles, etc...
- In wxPython this is done by wrapping a wxDC object and forwarding the
- appropriate calls to it. Notice also that colour and line styles are
- mapped on the wx.Pen() member of the wxDC. This means that we have some
- rudimentary pen management here.
-
+ This class stores a reference to a wxMemoryDC, and a
+ wxGraphicsContext that draws to it. Creating a wxGraphicsContext
+ seems to be fairly heavy, so these objects are cached based on the
+ bitmap object that is passed in.
+
The base GraphicsContext stores colors as a RGB tuple on the unit
interval, eg, (0.5, 0.0, 1.0). wxPython uses an int interval, but
since wxPython colour management is rather simple, I have not chosen
@@ -487,26 +439,30 @@
'dashed': wx.SHORT_DASH,
'dashdot': wx.DOT_DASH,
'dotted': wx.DOT }
- _lastWxDC = None
-
+ _cache = weakref.WeakKeyDictionary()
+
def __init__(self, bitmap, renderer):
GraphicsContextBase.__init__(self)
- wx.MemoryDC.__init__(self)
#assert self.Ok(), "wxMemoryDC not OK to use"
DEBUG_MSG("__init__()", 1, self)
- # Make sure (belt and braces!) that existing wxDC is not selected to
- # to a bitmap.
- if GraphicsContextWx._lastWxDC != None:
- GraphicsContextWx._lastWxDC.SelectObject(wx.NullBitmap)
-
- self.SelectObject(bitmap)
+ dc, gfx_ctx = self._cache.get(bitmap, (None, None))
+ if dc is None:
+ print "new dc"
+ dc = wx.MemoryDC()
+ dc.SelectObject(bitmap)
+ gfx_ctx = wx.GraphicsContext.Create(dc)
+ gfx_ctx._lastcliprect = None
+ self._cache[bitmap] = dc, gfx_ctx
+
self.bitmap = bitmap
- self.SetPen(wx.Pen('BLACK', 1, wx.SOLID))
- self._style=wx.SOLID
+ self.dc = dc
+ self.gfx_ctx = gfx_ctx
+ self._pen = wx.Pen('BLACK', 1, wx.SOLID)
+ gfx_ctx.SetPen(self._pen)
+ self._style = wx.SOLID
self.renderer = renderer
- GraphicsContextWx._lastWxDC = self
-
+
def select(self):
"""
Select the current bitmap into this wxDC instance
@@ -524,23 +480,6 @@
self.SelectObject(wx.NullBitmap)
self.IsSelected = False
- def set_clip_rectangle(self, rect):
- """
- Destroys previous clipping region and defines a new one.
- """
- DEBUG_MSG("set_clip_rectangle()", 1, self)
- self.select()
- l,b,w,h = rect
- # this appears to be version dependent'
- if hasattr(self, 'SetClippingRegionXY'):
- clipfunc = getattr(self, 'SetClippingRegionXY')
- else:
- clipfunc = getattr(self, 'SetClippingRegion')
-
- clipfunc(int(l), self.renderer.height - int(b+h),
- int(w), int(h))
- self.unselect()
-
def set_foreground(self, fg, isRGB=None):
"""
Set the foreground color. fg can be a matlab format string, a
@@ -556,12 +495,8 @@
self.select()
GraphicsContextBase.set_foreground(self, fg, isRGB)
- pen = self.GetPen()
- pen.SetColour(self.get_wxcolour())
- self.SetPen(pen)
- brush =wx.Brush(self.get_wxcolour(), wx.SOLID)
- self.SetBrush(brush)
- self.SetTextForeground(self.get_wxcolour())
+ self._pen.SetColour(self.get_wxcolour(self.get_rgb()))
+ self.gfx_ctx.SetPen(self._pen)
self.unselect()
def set_graylevel(self, frac):
@@ -573,11 +508,8 @@
DEBUG_MSG("set_graylevel()", 1, self)
self.select()
GraphicsContextBase.set_graylevel(self, frac)
- pen = self.GetPen()
- pen.SetColour(self.get_wxcolour())
- self.SetPen(pen)
- brush =wx.Brush(self.get_wxcolour(), wx.SOLID)
- self.SetBrush(brush)
+ self._pen.SetColour(self.get_wxcolour(self.get_rgb()))
+ self.gfx_ctx.SetPen(self._pen)
self.unselect()
def set_linewidth(self, w):
@@ -588,11 +520,10 @@
self.select()
if w>0 and w<1: w = 1
GraphicsContextBase.set_linewidth(self, w)
- pen = self.GetPen()
lw = int(self.renderer.points_to_pixels(self._linewidth))
if lw==0: lw = 1
- pen.SetWidth(lw)
- self.SetPen(pen)
+ self._pen.SetWidth(lw)
+ self.gfx_ctx.SetPen(self._pen)
self.unselect()
def set_capstyle(self, cs):
@@ -602,9 +533,8 @@
DEBUG_MSG("set_capstyle()", 1, self)
self.select()
GraphicsContextBase.set_capstyle(self, cs)
- pen = self.GetPen()
- pen.SetCap(GraphicsContextWx._capd[self._capstyle])
- self.SetPen(pen)
+ self._pen.SetCap(GraphicsContextWx._capd[self._capstyle])
+ self.gfx_ctx.SetPen(self._pen)
self.unselect()
def set_joinstyle(self, js):
@@ -614,9 +544,8 @@
DEBUG_MSG("set_joinstyle()", 1, self)
self.select()
GraphicsContextBase.set_joinstyle(self, js)
- pen = self.GetPen()
- pen.SetJoin(GraphicsContextWx._joind[self._joinstyle])
- self.SetPen(pen)
+ self._pen.SetJoin(GraphicsContextWx._joind[self._joinstyle])
+ self.gfx_ctx.SetPen(self._pen)
self.unselect()
def set_linestyle(self, ls):
@@ -629,25 +558,32 @@
try:
self._style = GraphicsContextWx._dashd_wx[ls]
except KeyError:
- self._style=wx.LONG_DASH# Style not used elsewhere...
+ self._style = wx.LONG_DASH# Style not used elsewhere...
# On MS Windows platform, only line width of 1 allowed for dash lines
if wx.Platform == '__WXMSW__':
self.set_linewidth(1)
- pen = self.GetPen()
- pen.SetStyle(self._style)
- self.SetPen(pen)
+ self._pen.SetStyle(self._style)
+ self.gfx_ctx.SetPen(self._pen)
self.unselect()
- def get_wxcolour(self):
+ def get_wxcolour(self, color):
"""return a wx.Colour from RGB format"""
DEBUG_MSG("get_wx_color()", 1, self)
- r, g, b = self.get_rgb()
- r *= 255
- g *= 255
- b *= 255
- return wx.Colour(red=int(r), green=int(g), blue=int(b))
+ if len(color) == 3:
+ r, g, b = color
+ r *= 255
+ g *= 255
+ b *= 255
+ return wx.Colour(red=int(r), green=int(g), blue=int(b))
+ else:
+ r, g, b, a = color
+ r *= 255
+ g *= 255
+ b *= 255
+ a *= 255
+ return wx.Colour(red=int(r), green=int(g), blue=int(b),
alpha=int(a))
class FigureCanvasWx(FigureCanvasBase, wx.Panel):
"""
@@ -783,7 +719,7 @@
self.macros = {} # dict from wx id to seq of macros
self.Printer_Init()
-
+
def Destroy(self, *args, **kwargs):
wx.Panel.Destroy(self, *args, **kwargs)
@@ -938,6 +874,9 @@
self.gui_repaint()
+ def draw_idle(self, *args, **kwargs):
+ pass
+
def draw(self, repaint=True):
"""
Render the figure using RendererWx instance renderer, or using a
@@ -1016,7 +955,7 @@
def _print_image(self, filename, filetype, *args, **kwargs):
origBitmap = self.bitmap
- l,b,width,height = self.figure.bbox.get_bounds()
+ l,b,width,height = self.figure.bbox.bounds
width = int(math.ceil(width))
height = int(math.ceil(height))
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins