Merge branch 'swt2c-palette'

This commit is contained in:
Robin Dunn
2016-08-05 13:20:37 -07:00
8 changed files with 242 additions and 4 deletions

View File

@@ -131,7 +131,6 @@ Other Dev Stuff
* dialup ??
* docmdi ??
* docview ??
* palette ??
* persist ??
* Add a _msw module that will contain classes and such that are only

View File

@@ -2205,6 +2205,7 @@
"NullIcon":"wx.",
"NullIconBundle":"wx.",
"NullImage":"wx.",
"NullPalette":"wx.",
"NullPen":"wx.",
"NullRegion":"wx.",
"ODCB_DCLICK_CYCLES":"wx.adv.",
@@ -2460,6 +2461,7 @@
"PageSetupDialogData":"wx.",
"PaintDC":"wx.",
"PaintEvent":"wx.",
"Palette":"wx.",
"PaletteChangedEvent":"wx.",
"Panel":"wx.",
"PanelNameStr":"wx.",

View File

@@ -94,6 +94,7 @@ INCLUDES = [ # base and core stuff
'graphics',
'imaglist',
'overlay',
'palette',
'renderer',
'rawbmp',

View File

@@ -84,7 +84,6 @@ def run():
# TODO: Add these classes for real :-)
module.insertItem(0, etgtools.WigCode("""\
// forward declarations
class wxPalette;
class wxExecuteEnv;
"""))

161
etg/palette.py Normal file
View File

@@ -0,0 +1,161 @@
#---------------------------------------------------------------------------
# Name: etg/palette.py
# Author: Scott Talbert
#
# Created: 31-Jul-2016
# Copyright: (c) 2016 by Total Control Software
# License: wxWindows License
#---------------------------------------------------------------------------
import etgtools
import etgtools.tweaker_tools as tools
PACKAGE = "wx"
MODULE = "_core"
NAME = "palette" # Base name of the file to generate to for this script
DOCSTRING = ""
# The classes and/or the basename of the Doxygen XML files to be processed by
# this script.
ITEMS = [ 'wxPalette' ]
#---------------------------------------------------------------------------
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.
c = module.find('wxPalette')
tools.removeVirtuals(c)
# Add a helper function for use with the Create method and the Ctor
# accepting RGB data.
c.addCppCode("""\
// a helper function to be used in the Create method and one of the Ctors
bool _paletteCreateHelper(wxPalette* self,
PyObject* red, PyObject* green, PyObject* blue) {
bool rval = false;
wxPyThreadBlocker blocker;
char* errMsg = "Expected a sequence of integer objects";
if (!PySequence_Check(red) || !PySequence_Check(green) || !PySequence_Check(blue)) {
PyErr_SetString(PyExc_TypeError, errMsg);
return rval;
}
Py_ssize_t count = PySequence_Size(red);
if (PySequence_Size(green) != count || PySequence_Size(blue) != count) {
PyErr_SetString(PyExc_ValueError, "Sequence lengths must be equal");
return rval;
}
unsigned char* redArray = new unsigned char[count];
unsigned char* greenArray = new unsigned char[count];
unsigned char* blueArray = new unsigned char[count];
for (Py_ssize_t i = 0; i < count; i++) {
PyObject* redItem = PySequence_ITEM(red, i);
PyObject* greenItem = PySequence_ITEM(green, i);
PyObject* blueItem = PySequence_ITEM(blue, i);
if (!wxPyInt_Check(redItem) || !wxPyInt_Check(greenItem) || !wxPyInt_Check(blueItem)) {
PyErr_SetString(PyExc_TypeError, errMsg);
goto pch_exit;
}
long redLong = wxPyInt_AsLong(redItem);
long greenLong = wxPyInt_AsLong(greenItem);
long blueLong = wxPyInt_AsLong(blueItem);
Py_DECREF(redItem);
Py_DECREF(greenItem);
Py_DECREF(blueItem);
if (redLong < 0 || redLong > 255 || greenLong < 0 || greenLong > 255 || blueLong < 0 || blueLong > 255) {
PyErr_SetString(PyExc_ValueError, "Sequence values must be in the 0..255 range");
goto pch_exit;
}
redArray[i] = redLong;
greenArray[i] = greenLong;
blueArray[i] = blueLong;
}
rval = self->Create(count, redArray, greenArray, blueArray);
pch_exit:
delete[] redArray;
delete[] greenArray;
delete[] blueArray;
return rval;
}
""")
#-----------------------------------------------------------------
# Replace the constructor accepting the arrays of RGB values with one that
# understands any Python sequence.
c.find('wxPalette').findOverload('red').ignore()
c.addCppCtor('(PyObject* red, PyObject* green, PyObject* blue)',
doc="""\
Creates a palette from a set of sequences of integers,
one for each red, green and blue color components.""",
body="""\
wxPalette* pal = new wxPalette;
_paletteCreateHelper(pal, red, green, blue);
if (PyErr_Occurred()) {
delete pal;
return NULL;
}
return pal;
""")
c.find('GetPixel.red').pyInt = True
c.find('GetPixel.green').pyInt = True
c.find('GetPixel.blue').pyInt = True
c.find('GetRGB').ignore()
c.addCppMethod('PyObject*', 'GetRGB', '(int pixel)',
doc="Returns RGB values for a given palette index.",
body="""\
unsigned char red;
unsigned char green;
unsigned char blue;
wxPyThreadBlocker blocker;
if (!self->GetRGB(pixel, &red, &green, &blue)) {
PyErr_SetString(PyExc_IndexError, "Pixel out of range");
return NULL;
}
PyObject* rv = PyTuple_New(3);
PyTuple_SetItem(rv, 0, wxPyInt_FromLong(red));
PyTuple_SetItem(rv, 1, wxPyInt_FromLong(green));
PyTuple_SetItem(rv, 2, wxPyInt_FromLong(blue));
return rv;
""")
# Replace the Create method with one that understands any kind of Python sequence
c.find('Create').ignore()
c.addCppMethod('PyObject*', 'Create', '(PyObject* red, PyObject* green, PyObject* blue)',
doc="Creates a palette from 3 sequences of integers, one for each red, blue or green component.",
body="""\
bool rval = _paletteCreateHelper(self, red, green, blue);
wxPyThreadBlocker blocker;
if (PyErr_Occurred())
return NULL;
if (rval)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
""")
#-----------------------------------------------------------------
tools.doCommonTweaks(module)
tools.runGenerators(module)
#---------------------------------------------------------------------------
if __name__ == '__main__':
run()

View File

@@ -824,7 +824,9 @@ from .%s import *
stream.write('%s%%MethodCode\n' % indent)
stream.write(indent+' '*4)
if method.isCtor:
stream.write('sipCpp = %s(%s);\n' % (fname, pnames))
# _THREAD macros are intentionally not used in this case
stream.write('PyErr_Clear();\n')
stream.write('%ssipCpp = %s(%s);\n' % (indent+' '*4, fname, pnames))
elif method.isDtor:
stream.write('PyErr_Clear();\n')

74
unittests/test_palette.py Normal file
View File

@@ -0,0 +1,74 @@
import unittest
from unittests import wtc
import wx
#---------------------------------------------------------------------------
class palette_Tests(wtc.WidgetTestCase):
def test_paletteCtor1(self):
# test with a bytearray like the original impl
rgb = bytearray(range(256))
p = wx.Palette(rgb, rgb, rgb)
self.assertTrue(p.IsOk())
self.assertTrue(p.GetColoursCount() == 256)
self.assertTrue(p.GetPixel(42, 42, 42) == 42)
self.assertTrue(p.GetRGB(64) == (64, 64, 64))
with self.assertRaises(IndexError):
p.GetRGB(257)
def test_paletteCtor2(self):
# and do the same using a list
rgb = list(range(256))
p = wx.Palette(rgb, rgb, rgb)
self.assertTrue(p.IsOk())
self.assertTrue(p.GetColoursCount() == 256)
self.assertTrue(p.GetPixel(42, 42, 42) == 42)
self.assertTrue(p.GetRGB(64) == (64, 64, 64))
with self.assertRaises(IndexError):
p.GetRGB(257)
def test_paletteCtor3(self):
p = wx.Palette()
def test_paletteCtor4(self):
p1 = wx.Palette()
p2 = wx.Palette(p1)
def test_paletteCreate1(self):
p = wx.Palette()
with self.assertRaises(TypeError): # not sequences
p.Create(1, 2, 3)
with self.assertRaises(ValueError): # not the same length
p.Create((1, 2, 3), (1, 2, 3), (1, 2))
with self.assertRaises(TypeError): # not integers
p.Create((1, 2, 3), ("1", "2", "3"), (1, 2, 3))
with self.assertRaises(ValueError): # outside of 0..255 range
p.Create((257, 2, 3), (1, 2, 3), (1, 2, 3))
with self.assertRaises(ValueError): # outside of 0..255 range
p.Create((1, 2, 3), (-1, 2, 3), (1, 2, 3))
# range is okay, checking start and end
p.Create((1, 2, 3, 0), (1, 2, 3, 4), (1, 2, 3, 4))
p.Create((1, 2, 3, 255), (1, 2, 3, 4), (1, 2, 3, 4))
def test_paletteCreate2(self):
p = wx.Palette()
# 3 different kinds of sequences :)
self.assertTrue(p.Create((1, 2, 3), [4, 5, 6], bytearray([7, 8, 9])))
self.assertTrue(p.GetRGB(1) == (2, 5, 8))
def test_nullPalette(self):
wx.NullPalette
#---------------------------------------------------------------------------
if __name__ == '__main__':
unittest.main()