mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-09 05:20:08 +01:00
Lots of enhancments and additions for wxGraphics classes. Added unittests too.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@69402 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
151
etg/graphics.py
151
etg/graphics.py
@@ -1,6 +1,7 @@
|
||||
#---------------------------------------------------------------------------
|
||||
# Name: etg/graphics.py
|
||||
# Author: Kevin Ollivier
|
||||
# Robin Dunn
|
||||
#
|
||||
# Created: 10-Sept-2011
|
||||
# Copyright: (c) 2011 by Kevin Ollivier
|
||||
@@ -18,26 +19,28 @@ DOCSTRING = ""
|
||||
# The classes and/or the basename of the Doxygen XML files to be processed by
|
||||
# this script.
|
||||
ITEMS = [
|
||||
'wxGraphicsObject',
|
||||
'wxGraphicsBitmap',
|
||||
'wxGraphicsBrush',
|
||||
'wxGraphicsContext',
|
||||
'wxGraphicsFont',
|
||||
'wxGraphicsPen',
|
||||
'wxGraphicsContext',
|
||||
'wxGraphicsGradientStop',
|
||||
'wxGraphicsGradientStops',
|
||||
'wxGraphicsMatrix',
|
||||
'wxGraphicsObject',
|
||||
'wxGraphicsPath',
|
||||
'wxGraphicsPen',
|
||||
'wxGraphicsRenderer',
|
||||
]
|
||||
|
||||
OTHERDEPS = [ 'src/Point2D_helpers.cpp']
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def run():
|
||||
# Parse the XML file(s) building a collection of Extractor objects
|
||||
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
|
||||
etgtools.parseDoxyXML(module, ITEMS)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
# Tweak the parsed meta objects in the module object as needed for
|
||||
# customizing the generated code and docstrings.
|
||||
@@ -46,14 +49,31 @@ def run():
|
||||
|
||||
def markFactories(klass):
|
||||
for func in klass.allItems():
|
||||
if isinstance(func, etgtools.FunctionDef) and func.name.startswith('Create'):
|
||||
if isinstance(func, etgtools.FunctionDef) \
|
||||
and func.name.startswith('Create') \
|
||||
and '*' in func.type:
|
||||
func.factory = True
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
c = module.find('wxGraphicsObject')
|
||||
assert isinstance(c, etgtools.ClassDef)
|
||||
c.addCppMethod('bool', 'IsOk', '()', 'return !self->IsNull();')
|
||||
c.addCppMethod('int', '__nonzero__', '()', "return !self->IsNull();")
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
c = module.find('wxGraphicsContext')
|
||||
assert isinstance(c, etgtools.ClassDef)
|
||||
markFactories(c)
|
||||
tools.removeVirtuals(c)
|
||||
c.abstract = True
|
||||
|
||||
# ensure that the target DC lives as long as the GC does
|
||||
for m in c.find('Create').all():
|
||||
for p in m.items:
|
||||
if 'DC' in p.name or p.name == 'image':
|
||||
p.keepReference = True
|
||||
|
||||
|
||||
# FIXME: Handle wxEnhMetaFileDC?
|
||||
c.find('Create').findOverload('wxEnhMetaFileDC').ignore()
|
||||
@@ -61,16 +81,98 @@ def run():
|
||||
# SIP doesn't like default parameter values to use dereference syntax,
|
||||
# (such as "col = *wxBLACK") so tweak the syntax a bit by using a macro.
|
||||
c.addHeaderCode("#define BLACK *wxBLACK")
|
||||
for m in [c.find('CreateFont')] + c.find('CreateFont').overloads:
|
||||
for m in c.find('CreateFont').all():
|
||||
m.find('col').default = 'BLACK'
|
||||
|
||||
m = c.find('GetPartialTextExtents')
|
||||
m.find('widths').ignore()
|
||||
m.type = 'wxArrayDouble*'
|
||||
m.setCppCode("""\
|
||||
wxArrayDouble rval;
|
||||
self->GetPartialTextExtents(*text, rval);
|
||||
return new wxArrayDouble(rval);
|
||||
""")
|
||||
|
||||
m = c.find('GetTextExtent')
|
||||
m.pyName = 'GetFullTextExtent'
|
||||
m.find('width').out = True
|
||||
m.find('height').out = True
|
||||
m.find('descent').out = True
|
||||
m.find('externalLeading').out = True
|
||||
|
||||
m2 = c.addCppMethod('PyObject*', 'GetTextExtent', '(const wxString& text)',
|
||||
pyArgsString="(text) -> (width, height)",
|
||||
doc="Gets the dimensions of the string using the currently selected font.",
|
||||
body="""\
|
||||
wxDouble width = 0.0, height = 0.0;
|
||||
self->GetTextExtent(*text, &width, &height, NULL, NULL);
|
||||
return sipBuildResult(0, "(dd)", width, height);
|
||||
""")
|
||||
c.items.remove(m2)
|
||||
c.insertItemAfter(m, m2)
|
||||
|
||||
c.addPyCode("GraphicsContext.DrawRotatedText = wx.deprecated(GraphicsContext.DrawText)")
|
||||
|
||||
|
||||
c.includeCppCode('src/Point2D_helpers.cpp')
|
||||
|
||||
# we'll reimplement this overload as StrokeLineSegments
|
||||
c.find('StrokeLines').findOverload('beginPoints').ignore()
|
||||
c.addCppMethod('void', 'StrokeLineSegments', '(PyObject* beginPoints, PyObject* endPoints)',
|
||||
pyArgsString="(beginPoint2Ds, endPoint2Ds)",
|
||||
doc="Stroke disconnected lines from begin to end points.",
|
||||
body="""\
|
||||
size_t c1, c2, count;
|
||||
wxPoint2D* beginP = wxPoint2D_array_helper(beginPoints, &c1);
|
||||
wxPoint2D* endP = wxPoint2D_array_helper(endPoints, &c2);
|
||||
|
||||
if ( beginP != NULL && endP != NULL ) {
|
||||
count = wxMin(c1, c2);
|
||||
self->StrokeLines(count, beginP, endP);
|
||||
}
|
||||
delete [] beginP;
|
||||
delete [] endP;
|
||||
""")
|
||||
|
||||
# Also reimplement the main StrokeLines method to reuse the same helper
|
||||
# function as StrokLineSegments
|
||||
m = c.find('StrokeLines').findOverload('points').ignore()
|
||||
c.addCppMethod('void', 'StrokeLines', '(PyObject* points)',
|
||||
pyArgsString="(point2Ds)",
|
||||
doc="Stroke lines conencting all the points.",
|
||||
body="""\
|
||||
size_t count;
|
||||
wxPoint2D* ptsArray = wxPoint2D_array_helper(points, &count);
|
||||
|
||||
if ( ptsArray != NULL ) {
|
||||
self->StrokeLines(count, ptsArray);
|
||||
delete [] ptsArray;
|
||||
}
|
||||
""")
|
||||
|
||||
# and once more for DrawLines
|
||||
m = c.find('DrawLines').ignore()
|
||||
c.addCppMethod('void', 'DrawLines', '(PyObject* points, wxPolygonFillMode fillStyle = wxODDEVEN_RULE)',
|
||||
pyArgsString="(point2Ds, fillStyle=ODDEVEN_RULE)",
|
||||
doc="Draws a polygon.",
|
||||
body="""\
|
||||
size_t count;
|
||||
wxPoint2D* ptsArray = wxPoint2D_array_helper(points, &count);
|
||||
|
||||
if ( ptsArray != NULL ) {
|
||||
self->DrawLines(count, ptsArray, fillStyle);
|
||||
delete [] ptsArray;
|
||||
}
|
||||
""")
|
||||
|
||||
#---------------------------------------------
|
||||
c = module.find('wxGraphicsPath')
|
||||
tools.removeVirtuals(c)
|
||||
c.find('GetBox').findOverload('wxDouble *x, wxDouble *y').ignore()
|
||||
c.find('GetCurrentPoint').findOverload('wxDouble *x, wxDouble *y').ignore()
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
c = module.find('wxGraphicsRenderer')
|
||||
tools.removeVirtuals(c)
|
||||
markFactories(c)
|
||||
@@ -80,12 +182,43 @@ def run():
|
||||
c.find('CreateContext').findOverload('wxEnhMetaFileDC').ignore()
|
||||
|
||||
# See above
|
||||
for m in [c.find('CreateFont')] + c.find('CreateFont').overloads:
|
||||
for m in c.find('CreateFont').all():
|
||||
m.find('col').default = 'BLACK'
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
c = module.find('wxGraphicsMatrix')
|
||||
tools.removeVirtuals(c)
|
||||
|
||||
c.find('Concat').overloads = []
|
||||
c.find('IsEqual').overloads = []
|
||||
|
||||
c.find('Get.a').out = True
|
||||
c.find('Get.b').out = True
|
||||
c.find('Get.c').out = True
|
||||
c.find('Get.d').out = True
|
||||
c.find('Get.tx').out = True
|
||||
c.find('Get.ty').out = True
|
||||
|
||||
c.find('TransformDistance.dx').inOut = True
|
||||
c.find('TransformDistance.dy').inOut = True
|
||||
|
||||
c.find('TransformPoint.x').inOut = True
|
||||
c.find('TransformPoint.y').inOut = True
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
c = module.find('wxGraphicsGradientStops')
|
||||
c.addCppMethod('SIP_SSIZE_T', '__len__', '()', body="return (SIP_SSIZE_T)self->GetCount();")
|
||||
c.addCppMethod('wxGraphicsGradientStop*', '__getitem__', '(size_t n)',
|
||||
pyArgsString='(n)',
|
||||
body="return new wxGraphicsGradientStop(self->Item(n));")
|
||||
|
||||
|
||||
#---------------------------------------------
|
||||
# Use the pyNames we set for these classes in geometry.py so the old
|
||||
# names do not show up in the docstrings, etc.
|
||||
tools.changeTypeNames(module, 'wxPoint2DDouble', 'wxPoint2D')
|
||||
tools.changeTypeNames(module, 'wxRect2DDouble', 'wxRect2D')
|
||||
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
|
||||
53
src/Point2D_helpers.cpp
Normal file
53
src/Point2D_helpers.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
#define sipType_wxPoint2D sipType_wxPoint2DDouble
|
||||
|
||||
// Convert a Python sequence of 2-tuples of numbers or wx.Point2D objects into a
|
||||
// C array of wxPoint2D instances
|
||||
static
|
||||
wxPoint2D* wxPoint2D_array_helper(PyObject* source, size_t *count)
|
||||
{
|
||||
wxPoint2D* array;
|
||||
Py_ssize_t idx, len;
|
||||
|
||||
// ensure that it is a sequence
|
||||
if (! PySequence_Check(source))
|
||||
goto error0;
|
||||
// ensure it is not a string or unicode object (they are sequences too)
|
||||
else if (PyString_Check(source) || PyUnicode_Check(source))
|
||||
goto error0;
|
||||
// ensure each item can be converted to wxPoint2D
|
||||
else {
|
||||
len = PySequence_Length(source);
|
||||
for (idx=0; idx<len; idx++) {
|
||||
PyObject* item = PySequence_ITEM(source, idx);
|
||||
if (!sipCanConvertToType(item, sipType_wxPoint2D, SIP_NOT_NONE)) {
|
||||
Py_DECREF(item);
|
||||
goto error0;
|
||||
}
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
|
||||
// The length of the sequence is returned in count.
|
||||
*count = len;
|
||||
array = new wxPoint2D[*count];
|
||||
if (!array) {
|
||||
PyErr_SetString(PyExc_MemoryError, "Unable to allocate temporary array");
|
||||
return NULL;
|
||||
}
|
||||
for (idx=0; idx<len; idx++) {
|
||||
PyObject* obj = PySequence_ITEM(source, idx);
|
||||
int state = 0;
|
||||
int err = 0;
|
||||
wxPoint2D* item = reinterpret_cast<wxPoint2D*>(
|
||||
sipConvertToType(obj, sipType_wxPoint2D, NULL, 0, &state, &err));
|
||||
array[idx] = *item;
|
||||
sipReleaseType((void*)item, sipType_wxPoint2D, state); // delete temporary instances
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
return array;
|
||||
|
||||
error0:
|
||||
PyErr_SetString(PyExc_TypeError, "Expected a sequence of length-2 sequences or wxPoint2D objects.");
|
||||
return NULL;
|
||||
}
|
||||
155
unittests/test_graphics.py
Normal file
155
unittests/test_graphics.py
Normal file
@@ -0,0 +1,155 @@
|
||||
import imp_unittest, unittest
|
||||
import wtc
|
||||
import wx
|
||||
import os
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class graphics_Tests(wtc.WidgetTestCase):
|
||||
|
||||
def test_gcCreate1(self):
|
||||
gc = wx.GraphicsContext.Create(wx.ClientDC(self.frame))
|
||||
self.assertTrue(gc.IsOk())
|
||||
|
||||
|
||||
def test_gcCreate2(self):
|
||||
bmp = wx.Bitmap(100,100)
|
||||
mdc = wx.MemoryDC(bmp)
|
||||
gc = wx.GraphicsContext.Create(mdc)
|
||||
self.assertTrue(gc.IsOk())
|
||||
|
||||
def test_gcCreate3(self):
|
||||
img = wx.Image(100,100)
|
||||
gc = wx.GraphicsContext.Create(img)
|
||||
self.assertTrue(gc.IsOk())
|
||||
|
||||
def test_gcCreateBitmap(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
self.assertTrue(gc.IsOk())
|
||||
bmp = wx.Bitmap(100,100)
|
||||
gb = gc.CreateBitmap(bmp)
|
||||
self.assertTrue(gb.IsOk())
|
||||
self.assertTrue(isinstance(gb, wx.GraphicsBitmap))
|
||||
|
||||
img = wx.Image(100,100)
|
||||
gb = gc.CreateBitmapFromImage(img)
|
||||
self.assertTrue(gb.IsOk())
|
||||
gb = gc.CreateSubBitmap(gb, 5, 5, 25, 25)
|
||||
self.assertTrue(gb.IsOk())
|
||||
|
||||
img = gb.ConvertToImage()
|
||||
self.assertTrue(img.IsOk())
|
||||
|
||||
def test_gcCreateBrush(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gb = gc.CreateBrush(wx.Brush('blue'))
|
||||
self.assertTrue(gb.IsOk())
|
||||
self.assertTrue(isinstance(gb, wx.GraphicsBrush))
|
||||
|
||||
def test_gcCreateFont(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gf = gc.CreateFont(wx.NORMAL_FONT)
|
||||
self.assertTrue(gf.IsOk())
|
||||
self.assertTrue(isinstance(gf, wx.GraphicsFont))
|
||||
|
||||
gf = gc.CreateFont(15, 'Courier')
|
||||
self.assertTrue(gf.IsOk())
|
||||
|
||||
def test_gcCreatePen(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gp = gc.CreatePen(wx.RED_PEN)
|
||||
self.assertTrue(gp.IsOk())
|
||||
self.assertTrue(isinstance(gp, wx.GraphicsPen))
|
||||
|
||||
|
||||
def test_gcCreatePath(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
p = gc.CreatePath()
|
||||
self.assertTrue(p.IsOk())
|
||||
self.assertTrue(isinstance(p, wx.GraphicsPath))
|
||||
|
||||
def test_gcCreateMatrix(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
m = gc.CreateMatrix()
|
||||
self.assertTrue(m.IsOk())
|
||||
self.assertTrue(isinstance(m, wx.GraphicsMatrix))
|
||||
|
||||
values = m.Get()
|
||||
self.assertTrue(len(values) == 6)
|
||||
|
||||
dx, dy = m.TransformDistance(5,6)
|
||||
x,y = m.TransformPoint(7,8)
|
||||
|
||||
|
||||
def test_gcTextExtents(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gf = gc.CreateFont(wx.NORMAL_FONT)
|
||||
gc.SetFont(gf)
|
||||
|
||||
ext = gc.GetPartialTextExtents("Hello")
|
||||
self.assertEqual(len(ext), 5)
|
||||
|
||||
w, h, d, e = gc.GetFullTextExtent("Hello")
|
||||
w, h = gc.GetTextExtent("Hello")
|
||||
|
||||
|
||||
|
||||
def test_gcStrokeLines1(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gc.SetPen(wx.Pen('blue', 2))
|
||||
|
||||
points = [ wx.Point2D(5,5),
|
||||
wx.Point2D(50,5),
|
||||
wx.Point2D(50,50),
|
||||
wx.Point2D(5,5),
|
||||
]
|
||||
gc.StrokeLines(points)
|
||||
|
||||
def test_gcStrokeLines2(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gc.SetPen(wx.Pen('blue', 2))
|
||||
points = [ (5,5), (50,5), wx.Point2D(50,50), (5,5) ]
|
||||
gc.StrokeLines(points)
|
||||
|
||||
def test_gcStrokeLines3(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gc.SetPen(wx.Pen('blue', 2))
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
points = [ (5,5), (50,5), 'not a point', (5,5) ]
|
||||
gc.StrokeLines(points)
|
||||
|
||||
def test_gcDrawLines(self):
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
gc.SetPen(wx.Pen('blue', 2))
|
||||
points = [ (5,5), (50,5), wx.Point2D(50,50), (5,5) ]
|
||||
gc.DrawLines(points)
|
||||
|
||||
|
||||
def test_gcGradientStops(self):
|
||||
gs1 = wx.GraphicsGradientStop('red', 0.25)
|
||||
gs2 = wx.GraphicsGradientStop('green', 0.50)
|
||||
gs3 = wx.GraphicsGradientStop('blue', 0.90)
|
||||
|
||||
gs1.Colour
|
||||
gs1.Position
|
||||
|
||||
stops = wx.GraphicsGradientStops()
|
||||
stops.Add(gs1)
|
||||
stops.Add(gs2)
|
||||
stops.Add('white', 0.75)
|
||||
stops.Add(gs3)
|
||||
|
||||
self.assertEqual(len(stops), 6) # 2 existing, plus 4 added
|
||||
gs = stops[2]
|
||||
self.assertTrue(gs.Position == 0.5)
|
||||
|
||||
gc = wx.GraphicsContext.Create(self.frame)
|
||||
b = gc.CreateLinearGradientBrush(0,0, 500, 100, stops)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user