def wx2Sphinx(name): """ Converts a wxWidgets specific string into a Phoenix-ReST-ready string. :param string `name`: any string. """ from etgtools.tweaker_tools import removeWxPrefix if '<' in name: name = name[0:name.index('<')] name = name.strip() newname = fullname = removeWxPrefix(name) if '.' in newname and len(newname) > 3: lookup, remainder = newname.split('.') remainder = '.%s' % remainder else: lookup = newname remainder = '' from etgtools.item_module_map import ItemModuleMap imm = ItemModuleMap() if lookup in imm: fullname = imm[lookup] + lookup + remainder return newname, fullname
def convertToPython(text): """ Converts the input `text` into a more ReSTified version of it. This involves the following steps: 1. Any C++ specific declaration (like ``unsigned``, ``size_t`` and so on is removed. 2. Lines starting with "Include file" or "#include" are ignored. 3. Uppercase constants (i.e., like ID_ANY, HORIZONTAL and so on) are converted into inline literals (i.e., ``ID_ANY``, ``HORIZONTAL``). 4. The "wx" prefix is removed from all the words in the input `text`. #*** :param string `text`: any string. :rtype: `string` """ from etgtools.tweaker_tools import removeWxPrefix from etgtools.item_module_map import ItemModuleMap newlines = [] unwanted = ['Include file', '#include'] for line in text.splitlines(): newline = [] for remove in unwanted: if remove in line: line = line[0:line.index(remove)] break spacer = ' ' * (len(line) - len(line.lstrip())) line = replaceCppItems(line) for word in RE_KEEP_SPACES.split(line): if word == VERSION: newline.append(word) continue newword = word for s in PUNCTUATION: newword = newword.replace(s, "") if newword in VALUE_MAP: word = word.replace(newword, VALUE_MAP[newword]) newline.append(word) continue if newword not in IGNORE and not newword.startswith('wx.'): word = removeWxPrefix(word) newword = removeWxPrefix(newword) if "::" in word and not word.endswith("::"): # Bloody SetCursorEvent... word = word.replace("::wx", ".") # *** word = word.replace("::", ".") word = "`%s`" % word newline.append(word) continue if (newword.upper() == newword and newword not in PUNCTUATION and newword not in IGNORE and len(newword.strip()) > 1 and not isNumeric(newword) and newword not in ['DC', 'GCDC']): if '``' not in newword and '()' not in word and '**' not in word: word = word.replace( newword, "``%s``" % ItemModuleMap().get_fullname(newword)) word = word.replace('->', '.') newline.append(word) newline = spacer + ''.join(newline) newline = newline.replace(':see:', '.. seealso::') newline = newline.replace(':note:', '.. note::') newlines.append(newline) formatted = "\n".join(newlines) formatted = formatted.replace('\\', '\\\\') return formatted
def pythonizeType(ptype, is_param): """ Replaces various C++ specific stuff with more Pythonized version of them, for parameter lists and return types (i.e., the `:param:` and `:rtype:` ReST roles). :param string `ptype`: any string; :param bool `is_param`: ``True`` if this is a parameter description, ``False`` if it is a return type. :rtype: `string` """ from etgtools.tweaker_tools import removeWxPrefix if 'size_t' in ptype: ptype = 'int' elif 'wx.' in ptype: ptype = ptype[3:] # *** else: ptype = wx2Sphinx(replaceCppItems(ptype))[1] ptype = ptype.replace('::', '.').replace('*&', '') ptype = ptype.replace('int const', 'int') ptype = ptype.replace('Uint32', 'int').replace('**', '').replace('Int32', 'int') ptype = ptype.replace('FILE', 'file') ptype = ptype.replace('boolean', 'bool') for item in ['unsignedchar', 'unsignedint', 'unsignedlong', 'unsigned']: ptype = ptype.replace(item, 'int') ptype = ptype.strip() ptype = removeWxPrefix(ptype) if '. wx' in ptype: #*** ptype = ptype.replace('. wx', '.') plower = ptype.lower() if plower == 'double': ptype = 'float' if plower in ['string', 'char', 'artid', 'artclient']: ptype = 'string' if plower in [ 'coord', 'byte', 'fileoffset', 'short', 'time_t', 'intptr', 'uintptr', 'windowid' ]: ptype = 'int' if plower in ['longlong']: ptype = 'long' cpp = ['ArrayString', 'ArrayInt', 'ArrayDouble'] python = ['list of strings', 'list of integers', 'list of floats'] for c, p in zip(cpp, python): ptype = ptype.replace(c, p) if 'Image.' in ptype: ptype = ptype.split('.')[-1] if 'FileName' in ptype: ptype = 'string' if ptype.endswith('&'): ptype = ptype[0:-1] if ' ' not in ptype: ptype = ':class:`%s`' % ptype else: if is_param and '.' in ptype: modules = list(MODULENAME_REPLACE.values()) modules.sort() modules = modules[1:] if ptype.split('.')[0] + '.' in modules: ptype = ':ref:`%s`' % ptype return ptype
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. # Add a ctor/factory for the Mac that can use the theme brush module.addCppCode("""\ #ifdef __WXMAC__ #include <wx/osx/private.h> #endif """) module.addCppFunction('wxColour*', 'MacThemeColour', '(int themeBrushID)', """\ #ifdef __WXMAC__ return new wxColour(wxMacCreateCGColorFromHITheme(themeBrushID)); #else wxPyRaiseNotImplemented(); return NULL; #endif """, factory=True) # Change this macro into a value so we wont have problems when SIP takes its # address module.addCppCode("""\ #undef wxTransparentColour wxColour wxTransparentColour(0, 0, 0, wxALPHA_TRANSPARENT); """) module.find('wxFromString').ignore() module.find('wxToString').ignore() module.find('wxALPHA_TRANSPARENT').type = 'const int' module.find('wxALPHA_OPAQUE').type = 'const int' c = module.find('wxColour') assert isinstance(c, etgtools.ClassDef) tools.removeVirtuals(c) # Hide the string ctor so our typemap will be invoked for the copy ctor instead. c.find('wxColour').findOverload('wxString').ignore() c.addProperty('Pixel GetPixel') c.addProperty('RGB GetRGB SetRGB') c.addProperty('RGBA GetRGBA SetRGBA') c.addProperty('red Red') c.addProperty('green Green') c.addProperty('blue Blue') c.addProperty('alpha Alpha') c.find('GetPixel').ignore() # We need to add a typcast c.addCppMethod( 'wxIntPtr*', 'GetPixel', '()', """\ #ifdef __WXGTK3__ return new wxIntPtr(0); #else return new wxIntPtr((wxIntPtr)self->GetPixel()); #endif """) # Set a flag on the return value and parameter types that are 'unsigned char' # such that they will be treated as an integer instead of a string. for item in c.allItems(): if hasattr(item, 'type') and item.type == 'unsigned char': item.pyInt = True c.find('ChangeLightness.r').inOut = True c.find('ChangeLightness.g').inOut = True c.find('ChangeLightness.b').inOut = True c.find('MakeDisabled.r').inOut = True c.find('MakeDisabled.g').inOut = True c.find('MakeDisabled.b').inOut = True c.find('MakeGrey.r').inOut = True c.find('MakeGrey.g').inOut = True c.find('MakeGrey.b').inOut = True c.find('MakeGrey').findOverload('double').find('r').inOut = True c.find('MakeGrey').findOverload('double').find('g').inOut = True c.find('MakeGrey').findOverload('double').find('b').inOut = True c.find('MakeMono.r').out = True c.find('MakeMono.g').out = True c.find('MakeMono.b').out = True # The stock Colour items are documented as simple pointers, but in # reality they are macros that evaluate to a function call that returns a # Colour pointer, and that is only valid *after* the wx.App object has # been created. That messes up the code that SIP generates for them. So # instead we will just create uninitialized colours in a block of Python # code, that will then be initialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxColour* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock colours will be initialized when the wx.App object is created.\n' for name in [ 'wxBLACK', 'wxBLUE', 'wxCYAN', 'wxGREEN', 'wxYELLOW', 'wxLIGHT_GREY', 'wxRED', 'wxWHITE', ]: item = module.find(name) item.ignore() pycode += '%s = Colour()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) c.addCppMethod('PyObject*', 'Get', '(bool includeAlpha=true)', """\ int red = -1; int green = -1; int blue = -1; int alpha = wxALPHA_OPAQUE; if (self->IsOk()) { red = self->Red(); green = self->Green(); blue = self->Blue(); alpha = self->Alpha(); } if (includeAlpha) return sipBuildResult(0, "(iiii)", red, green, blue, alpha); else return sipBuildResult(0, "(iii)", red, green, blue); """, pyArgsString="(includeAlpha=True) -> (r,g,b) or (r,g,b,a)", briefDoc="""\ Returns the RGB intensity values as a tuple, optionally the alpha value as well.""" ) # Add sequence protocol methods and other goodies c.addPyMethod('__str__', '(self)', 'return str(self.Get())') c.addPyMethod('__repr__', '(self)', 'return "wx.Colour"+str(self.Get())') c.addPyMethod('__len__', '(self)', 'return len(self.Get())') c.addPyMethod('__nonzero__', '(self)', 'return self.IsOk()') c.addPyMethod('__reduce__', '(self)', 'return (Colour, self.Get())') c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]') c.addPyMethod( '__setitem__', '(self, idx, val)', """\ if idx == 0: self.red = val elif idx == 1: self.green = val elif idx == 2: self.blue = val elif idx == 3: self.alpha = val else: raise IndexError """) c.addPyCode('Colour.__safe_for_unpickling__ = True') # Types that can be converted to wx.Colour: # wxColour (duh) # Sequence with 3 or 4 integers # String with color name or #RRGGBB or #RRGGBBAA format # None (converts to wxNullColour) c.allowNone = True c.convertFromPyObject = """\ // is it just a typecheck? if (!sipIsErr) { if (sipPy == Py_None) return 1; if (sipCanConvertToType(sipPy, sipType_wxColour, SIP_NO_CONVERTORS)) return 1; if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) return 1; if (PySequence_Check(sipPy)) { size_t len = PySequence_Size(sipPy); if (len != 3 && len != 4) return 0; // ensure all the items in the sequence are numbers for (int idx=0; idx<len; idx+=1) { PyObject* o = PySequence_ITEM(sipPy, idx); bool isNum = PyNumber_Check(o); Py_DECREF(o); if (!isNum) return 0; } return 1; } return 0; } // otherwise do the conversion // is it None? if (sipPy == Py_None) { *sipCppPtr = new wxColour(wxNullColour); return sipGetState(sipTransferObj); } // Is it a string? else if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) { wxString spec = Py2wxString(sipPy); if (!spec.empty() && spec.GetChar(0) == '#' && (spec.length() == 7 || spec.length() == 9)) { // It's #RRGGBB[AA] long red, green, blue; red = green = blue = 0; spec.Mid(1,2).ToLong(&red, 16); spec.Mid(3,2).ToLong(&green, 16); spec.Mid(5,2).ToLong(&blue, 16); if (spec.length() == 7) // no alpha *sipCppPtr = new wxColour(red, green, blue); else { // yes alpha long alpha; spec.Mid(7,2).ToLong(&alpha, 16); *sipCppPtr = new wxColour(red, green, blue, alpha); } return sipGetState(sipTransferObj); } else { // assume it's a colour name // check if alpha is there too int pos; if (((pos = spec.Find(':', true)) != wxNOT_FOUND) && (pos == spec.length()-3)) { long alpha; spec.Right(2).ToLong(&alpha, 16); wxColour c = wxColour(spec.Left(spec.length()-3)); *sipCppPtr = new wxColour(c.Red(), c.Green(), c.Blue(), alpha); } else *sipCppPtr = new wxColour(spec); return sipGetState(sipTransferObj); } } // Is it a 3 or 4 element sequence? else if (PySequence_Check(sipPy)) { size_t len = PyObject_Length(sipPy); PyObject* o1 = PySequence_GetItem(sipPy, 0); PyObject* o2 = PySequence_GetItem(sipPy, 1); PyObject* o3 = PySequence_GetItem(sipPy, 2); if (len == 3) *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3)); else { PyObject* o4 = PySequence_GetItem(sipPy, 3); *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3), wxPyInt_AsLong(o4)); Py_DECREF(o4); } Py_DECREF(o1); Py_DECREF(o2); Py_DECREF(o3); return sipGetState(sipTransferObj); } // if we get this far then it must already be a wxColour instance *sipCppPtr = reinterpret_cast<wxColour*>(sipConvertToType( sipPy, sipType_wxColour, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); return 0; // not a new instance """ module.addPyCode( 'NamedColour = wx.deprecated(Colour, "Use Colour instead.")') # Just for TESTING, remove it later module.addCppCode("""\ wxColour testColourTypeMap(const wxColour& c) { return c; } """) module.addItem( etgtools.WigCode("""\ wxColour testColourTypeMap(const wxColour& c); """)) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
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. # Add a ctor/factory for the Mac that can use the theme brush module.addCppCode("""\ #ifdef __WXMAC__ #include <wx/osx/private.h> #endif """) module.addCppFunction('wxColour*', 'MacThemeColour', '(int themeBrushID)', """\ #ifdef __WXMAC__ return new wxColour(wxMacCreateCGColorFromHITheme(themeBrushID)); #else wxPyRaiseNotImplemented(); return NULL; #endif """, factory=True) # Change this macro into a value so we wont have problems when SIP takes its # address module.addCppCode("""\ #undef wxTransparentColour wxColour wxTransparentColour(0, 0, 0, wxALPHA_TRANSPARENT); """) module.find('wxFromString').ignore() module.find('wxToString').ignore() module.find('wxALPHA_TRANSPARENT').type = 'const int' module.find('wxALPHA_OPAQUE').type = 'const int' c = module.find('wxColour') assert isinstance(c, etgtools.ClassDef) tools.removeVirtuals(c) # Just set mustHaveApp for the copy ctor as it may need to use the colour # database to look up color names. c.find('wxColour').findOverload('const wxColour &').mustHaveApp() # Hide the string ctor so our typemap will be invoked for the copy ctor instead. c.find('wxColour').findOverload('wxString').ignore() c.addProperty('Pixel GetPixel') c.addProperty('RGB GetRGB SetRGB') c.addProperty('RGBA GetRGBA SetRGBA') c.addProperty('red Red') c.addProperty('green Green') c.addProperty('blue Blue') c.addProperty('alpha Alpha') c.find('GetPixel').ignore() # We need to add a typcast c.addCppMethod('wxIntPtr*', 'GetPixel', '()', """\ #ifdef __WXGTK3__ return new wxIntPtr(0); #else return new wxIntPtr((wxIntPtr)self->GetPixel()); #endif """) # Set a flag on the return value and parameter types that are 'unsigned char' # such that they will be treated as an integer instead of a string. for item in c.allItems(): if hasattr(item, 'type') and item.type == 'unsigned char': item.pyInt = True c.find('ChangeLightness.r').inOut = True c.find('ChangeLightness.g').inOut = True c.find('ChangeLightness.b').inOut = True c.find('MakeDisabled.r').inOut = True c.find('MakeDisabled.g').inOut = True c.find('MakeDisabled.b').inOut = True c.find('MakeGrey.r').inOut = True c.find('MakeGrey.g').inOut = True c.find('MakeGrey.b').inOut = True c.find('MakeGrey').findOverload('double').find('r').inOut = True c.find('MakeGrey').findOverload('double').find('g').inOut = True c.find('MakeGrey').findOverload('double').find('b').inOut = True c.find('MakeMono.r').out = True c.find('MakeMono.g').out = True c.find('MakeMono.b').out = True # The stock Colour items are documented as simple pointers, but in # reality they are macros that evaluate to a function call that returns a # Colour pointer, and that is only valid *after* the wx.App object has # been created. That messes up the code that SIP generates for them. So # instead we will just create uninitialized colours in a block of Python # code, that will then be initialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxColour* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock colours will be initialized when the wx.App object is created.\n' for name in [ 'wxBLACK', 'wxBLUE', 'wxCYAN', 'wxGREEN', 'wxYELLOW', 'wxLIGHT_GREY', 'wxRED', 'wxWHITE', ]: item = module.find(name) item.ignore() pycode += '%s = Colour()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) c.addCppMethod('PyObject*', 'Get', '(bool includeAlpha=true)', """\ int red = -1; int green = -1; int blue = -1; int alpha = wxALPHA_OPAQUE; if (self->IsOk()) { red = self->Red(); green = self->Green(); blue = self->Blue(); alpha = self->Alpha(); } wxPyThreadBlocker blocker; if (includeAlpha) return sipBuildResult(0, "(iiii)", red, green, blue, alpha); else return sipBuildResult(0, "(iii)", red, green, blue); """, pyArgsString="(includeAlpha=True) -> (r,g,b) or (r,g,b,a)", briefDoc="""\ Returns the RGB intensity values as a tuple, optionally the alpha value as well.""") tools.addGetIMMethodTemplate(module, c, ['red', 'green', 'blue', 'alpha']) # Add sequence protocol methods and other goodies c.addPyMethod('__str__', '(self)', 'return str(self.Get())') c.addPyMethod('__repr__', '(self)', 'return "wx.Colour"+str(self.Get())') c.addPyMethod('__len__', '(self)', 'return len(self.Get())') c.addPyMethod('__nonzero__', '(self)', 'return self.IsOk()') c.addPyMethod('__reduce__', '(self)', 'return (Colour, self.Get())') c.addPyMethod('__getitem__', '(self, idx)', 'return self.Get()[idx]') c.addPyMethod('__setitem__', '(self, idx, val)', """\ if idx == 0: self.red = val elif idx == 1: self.green = val elif idx == 2: self.blue = val elif idx == 3: self.alpha = val else: raise IndexError """) c.addPyCode('Colour.__safe_for_unpickling__ = True') # Types that can be converted to wx.Colour: # wxColour (duh) # Sequence with 3 or 4 integers # String with color name or #RRGGBB or #RRGGBBAA format # None (converts to wxNullColour) c.allowNone = True c.convertFromPyObject = """\ // is it just a typecheck? if (!sipIsErr) { if (sipPy == Py_None) return 1; if (sipCanConvertToType(sipPy, sipType_wxColour, SIP_NO_CONVERTORS)) return 1; if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) return 1; if (wxPyNumberSequenceCheck(sipPy, 4) || wxPyNumberSequenceCheck(sipPy, 3)) { return 1; } return 0; } // otherwise do the conversion // is it None? if (sipPy == Py_None) { *sipCppPtr = new wxColour(wxNullColour); return sipGetState(sipTransferObj); } // Is it a string? else if (PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)) { wxString spec = Py2wxString(sipPy); if (!spec.empty() && spec.GetChar(0) == '#' && (spec.length() == 7 || spec.length() == 9)) { // It's #RRGGBB[AA] long red, green, blue; red = green = blue = 0; spec.Mid(1,2).ToLong(&red, 16); spec.Mid(3,2).ToLong(&green, 16); spec.Mid(5,2).ToLong(&blue, 16); if (spec.length() == 7) // no alpha *sipCppPtr = new wxColour(red, green, blue); else { // yes alpha long alpha; spec.Mid(7,2).ToLong(&alpha, 16); *sipCppPtr = new wxColour(red, green, blue, alpha); } return sipGetState(sipTransferObj); } else { // assume it's a colour name // check if alpha is there too int pos; if (((pos = spec.Find(':', true)) != wxNOT_FOUND) && (pos == spec.length()-3)) { long alpha; spec.Right(2).ToLong(&alpha, 16); wxColour c = wxColour(spec.Left(spec.length()-3)); *sipCppPtr = new wxColour(c.Red(), c.Green(), c.Blue(), alpha); } else *sipCppPtr = new wxColour(spec); return sipGetState(sipTransferObj); } } // Is it a sequence? (if so then length was checked above) else if (wxPyNumberSequenceCheck(sipPy)) { size_t len = PySequence_Size(sipPy); PyObject* o1 = PySequence_ITEM(sipPy, 0); PyObject* o2 = PySequence_ITEM(sipPy, 1); PyObject* o3 = PySequence_ITEM(sipPy, 2); if (len == 3) *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3)); else { PyObject* o4 = PySequence_ITEM(sipPy, 3); *sipCppPtr = new wxColour(wxPyInt_AsLong(o1), wxPyInt_AsLong(o2), wxPyInt_AsLong(o3), wxPyInt_AsLong(o4)); Py_DECREF(o4); } Py_DECREF(o1); Py_DECREF(o2); Py_DECREF(o3); return sipGetState(sipTransferObj); } // if we get this far then it must already be a wxColour instance *sipCppPtr = reinterpret_cast<wxColour*>(sipConvertToType( sipPy, sipType_wxColour, sipTransferObj, SIP_NO_CONVERTORS, 0, sipIsErr)); return 0; // not a new instance """ module.addPyCode('NamedColour = wx.deprecated(Colour, "Use Colour instead.")') # Just for TESTING, remove it later module.addCppCode("""\ wxColour testColourTypeMap(const wxColour& c) { return c; } """) module.addItem(etgtools.WigCode("""\ wxColour testColourTypeMap(const wxColour& c); """)) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
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('wxFontInfo') assert isinstance(c, etgtools.ClassDef) ctor = c.find('wxFontInfo').findOverload('T pointSize') ctor.find('pointSize').type = 'float' c = module.find('wxFont') assert isinstance(c, etgtools.ClassDef) tools.removeVirtuals(c) # Set mustHaveApp on all ctors except the default ctor for ctor in c.find('wxFont').all(): if ctor.isCtor and ctor.argsString != '()': ctor.mustHaveApp() for func in c.find('New').all(): func.mustHaveApp() c.find('GetDefaultEncoding').mustHaveApp() c.find('SetDefaultEncoding').mustHaveApp() # Tweak the documentation in this constructor a little, replacing the # link to another constructor with a simpler version of the text. ctor = c.find('wxFont').findOverload('int pointSize') # TODO: should implement an easier way to findDocNode() the node containing what we're looking for... ref = list(ctor.detailedDoc[0])[0] assert ref.text.startswith('wxFont(') ref.tag = 'para' ref.text = 'the constructor accepting a :ref:`wx.FontInfo`' # FFont factory function for backwards compatibility module.addCppFunction('wxFont*', 'FFont', """(int pointSize, wxFontFamily family, int flags = wxFONTFLAG_DEFAULT, const wxString& faceName = wxEmptyString, wxFontEncoding encoding = wxFONTENCODING_DEFAULT)""", pyArgsString="(pointSize, family, flags=FONTFLAG_DEFAULT, faceName=EmptyString, encoding=FONTENCODING_DEFAULT)", body="""\ wxFont* font = wxFont::New(pointSize, family, flags, *faceName, encoding); return font; """, factory=True) for item in c.findAll('New'): item.factory = True c.addProperty('Encoding GetEncoding SetEncoding') c.addProperty('FaceName GetFaceName SetFaceName') c.addProperty('Family GetFamily SetFamily') c.addProperty('NativeFontInfoDesc GetNativeFontInfoDesc SetNativeFontInfo') c.addProperty('NativeFontInfoUserDesc GetNativeFontInfoUserDesc SetNativeFontInfoUserDesc') c.addProperty('PointSize GetPointSize SetPointSize') c.addProperty('PixelSize GetPixelSize SetPixelSize') c.addProperty('Style GetStyle SetStyle') c.addProperty('Weight GetWeight SetWeight') # TODO, there is now an Underlined method so we can't have a # property of the same name. #c.addProperty('Underlined GetUnderlined SetUnderlined') #c.addProperty('Strikethrough GetStrikethrough SetStrikethrough') c.addCppMethod('int', '__nonzero__', '()', "return self->IsOk();") c.addCppMethod('int', '__bool__', '()', "return self->IsOk();") c.addCppMethod('void*', 'GetHFONT', '()', doc="Returns the font's native handle.", body="""\ #ifdef __WXMSW__ return self->GetHFONT(); #else return 0; #endif """) c.addCppMethod('void*', 'OSXGetCGFont', '()', doc="Returns the font's native handle.", body="""\ #ifdef __WXMAC__ return self->OSXGetCGFont(); #else return 0; #endif """) c.addCppMethod('void*', 'GetPangoFontDescription', '()', doc="Returns the font's native handle.", body="""\ #ifdef __WXGTK__ return self->GetNativeFontInfo()->description; #else return 0; #endif """) c.find('AddPrivateFont').setCppCode("""\ #if wxUSE_PRIVATE_FONTS return wxFont::AddPrivateFont(*filename); #else wxPyRaiseNotImplemented(); return false; #endif """) c.addCppMethod('bool', 'CanUsePrivateFont', '()', isStatic=True, doc="Returns ``True`` if this build of wxPython supports using :meth:`AddPrivateFont`.", body="return wxUSE_PRIVATE_FONTS;") # The stock Font items are documented as simple pointers, but in reality # they are macros that evaluate to a function call that returns a font # pointer, and that is only valid *after* the wx.App object has been # created. That messes up the code that SIP generates for them, so we need # to come up with another solution. So instead we will just create # uninitialized fonts in a block of Python code, that will then be # initialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxFont* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock fonts will be initialized when the wx.App object is created.\n' for item in module: if '_FONT' in item.name: item.ignore() pycode += '%s = Font()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) # it is delay-initialized, see stockgdi.sip module.find('wxTheFontList').ignore() module.find('wxFromString').ignore() module.find('wxToString').ignore() c.addPyMethod('SetNoAntiAliasing', '(self, no=True)', 'pass', deprecated=True) c.addPyMethod('GetNoAntiAliasing', '(self)', 'pass', deprecated=True) # Some aliases that should be phased out eventually, (sooner rather than # later.) They are already gone (or wrapped by an #if) in the C++ code, # and so are not found in the documentation... module.addPyCode("""\ wx.DEFAULT = int(wx.FONTFAMILY_DEFAULT) wx.DECORATIVE = int(wx.FONTFAMILY_DECORATIVE) wx.ROMAN = int(wx.FONTFAMILY_ROMAN) wx.SCRIPT = int(wx.FONTFAMILY_SCRIPT) wx.SWISS = int(wx.FONTFAMILY_SWISS) wx.MODERN = int(wx.FONTFAMILY_MODERN) wx.TELETYPE = int(wx.FONTFAMILY_TELETYPE) wx.NORMAL = int(wx.FONTWEIGHT_NORMAL) wx.LIGHT = int(wx.FONTWEIGHT_LIGHT) wx.BOLD = int(wx.FONTWEIGHT_BOLD) wx.NORMAL = int(wx.FONTSTYLE_NORMAL) wx.ITALIC = int(wx.FONTSTYLE_ITALIC) wx.SLANT = int(wx.FONTSTYLE_SLANT) """) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
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('wxFont') assert isinstance(c, etgtools.ClassDef) tools.removeVirtuals(c) # FFont factory function for backwards compatibility module.addCppFunction('wxFont*', 'FFont', """(int pointSize, wxFontFamily family, int flags = wxFONTFLAG_DEFAULT, const wxString& faceName = wxEmptyString, wxFontEncoding encoding = wxFONTENCODING_DEFAULT)""", pyArgsString="(pointSize, family, flags=FONTFLAG_DEFAULT, faceName=EmptyString, encoding=FONTENCODING_DEFAULT)", body="""\ wxFont* font = wxFont::New(pointSize, family, flags, *faceName, encoding); return font; """, factory=True) for item in c.findAll('New'): item.factory = True c.addProperty('Encoding GetEncoding SetEncoding') c.addProperty('FaceName GetFaceName SetFaceName') c.addProperty('Family GetFamily SetFamily') c.addProperty('NativeFontInfoDesc GetNativeFontInfoDesc SetNativeFontInfo') c.addProperty('NativeFontInfoUserDesc GetNativeFontInfoUserDesc SetNativeFontInfoUserDesc') c.addProperty('PointSize GetPointSize SetPointSize') c.addProperty('PixelSize GetPixelSize SetPixelSize') c.addProperty('Style GetStyle SetStyle') c.addProperty('Weight GetWeight SetWeight') # TODO, there is now a Underlined method so we can't have a # property of the same name. #c.addProperty('Underlined GetUnderlined SetUnderlined') #c.addProperty('Strikethrough GetStrikethrough SetStrikethrough') c.addCppMethod('int', '__nonzero__', '()', """\ return self->IsOk(); """) c.addCppMethod('void*', 'GetHFONT', '()', doc="Returns the font's native handle.", body="""\ #ifdef __WXMSW__ return self->GetHFONT(); #else return 0; #endif """) c.addCppMethod('void*', 'OSXGetCGFont', '()', doc="Returns the font's native handle.", body="""\ #ifdef __WXMAC__ return self->OSXGetCGFont(); #else return 0; #endif """) c.addCppMethod('void*', 'GetPangoFontDescription', '()', doc="Returns the font's native handle.", body="""\ #ifdef __WXGTK__ return self->GetNativeFontInfo()->description; #else return 0; #endif """) # The stock Font items are documented as simple pointers, but in reality # they are macros that evaluate to a function call that returns a font # pointer, and that is only valid *after* the wx.App object has been # created. That messes up the code that SIP generates for them, so we need # to come up with another solution. So instead we will just create # uninitialized fonts in a block of Python code, that will then be # initialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxFont* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock fonts will be initialized when the wx.App object is created.\n' for item in module: if '_FONT' in item.name: item.ignore() pycode += '%s = Font()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) # it is delay-initialized, see stockgdi.sip module.find('wxTheFontList').ignore() module.find('wxFromString').ignore() module.find('wxToString').ignore() c.addPyMethod('SetNoAntiAliasing', '(self, no=True)', 'pass', deprecated=True) c.addPyMethod('GetNoAntiAliasing', '(self)', 'pass', deprecated=True) # Some aliases that should be phased out eventually, (sooner rather than # later.) They are already gone (or wrapped by an #if) in the C++ code, # and so are not found in the documentation... module.addPyCode("""\ wx.DEFAULT = int(wx.FONTFAMILY_DEFAULT) wx.DECORATIVE = int(wx.FONTFAMILY_DECORATIVE) wx.ROMAN = int(wx.FONTFAMILY_ROMAN) wx.SCRIPT = int(wx.FONTFAMILY_SCRIPT) wx.SWISS = int(wx.FONTFAMILY_SWISS) wx.MODERN = int(wx.FONTFAMILY_MODERN) wx.TELETYPE = int(wx.FONTFAMILY_TELETYPE) wx.NORMAL = int(wx.FONTWEIGHT_NORMAL) wx.LIGHT = int(wx.FONTWEIGHT_LIGHT) wx.BOLD = int(wx.FONTWEIGHT_BOLD) wx.NORMAL = int(wx.FONTSTYLE_NORMAL) wx.ITALIC = int(wx.FONTSTYLE_ITALIC) wx.SLANT = int(wx.FONTSTYLE_SLANT) """) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
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('wxCursor') assert isinstance(c, etgtools.ClassDef) # Set mustHaveApp on all ctors except the default ctor for ctor in c.find('wxCursor').all(): if ctor.isCtor and ctor.argsString != '()': ctor.mustHaveApp() c.find('wxCursor').findOverload('bits').ignore() c.find('wxCursor').findOverload('cursorName').find('type').default='wxBITMAP_TYPE_ANY' # TODO: This ctor ^^ in Classic has a custom implementation for wxGTK that # sets the hotspot. Is that still needed? c.addCppMethod('int', '__nonzero__', '()', "return self->IsOk();") c.addCppMethod('int', '__bool__', '()', "return self->IsOk();") c.addCppMethod('long', 'GetHandle', '()', """\ #ifdef __WXMSW__ return (long)self->GetHandle(); #else return 0; #endif""", briefDoc="Get the handle for the Cursor. Windows only.") c.addCppMethod('void', 'SetHandle', '(long handle)', """\ #ifdef __WXMSW__ self->SetHandle((WXHANDLE)handle); #endif""", briefDoc="Set the handle to use for this Cursor. Windows only.") # TODO: Classic has MSW-only getters and setters for width, height, depth, and size. # The stock Cursor items are documented as simple pointers, but in reality # they are macros that evaluate to a function call that returns a cursor # pointer, and that is only valid *after* the wx.App object has been # created. That messes up the code that SIP generates for them, so we need # to come up with another solution. So instead we will just create # uninitialized cursor in a block of Python code, that will then be # intialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxCursor* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock cursors will be initialized when the wx.App object is created.\n' for item in module: if '_CURSOR' in item.name: item.ignore() pycode += '%s = Cursor()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) # former renamed constructors module.addPyCode('StockCursor = wx.deprecated(Cursor, "Use Cursor instead.")') module.addPyCode('CursorFromImage = wx.deprecated(Cursor, "Use Cursor instead.")') #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
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('wxBrush') assert isinstance(c, etgtools.ClassDef) tools.removeVirtuals(c) # Set mustHaveApp on all ctors except the default ctor for ctor in c.find('wxBrush').all(): if ctor.isCtor and ctor.argsString != '()': ctor.mustHaveApp() c.addCppMethod('int', '__nonzero__', '()', "return self->IsOk();") c.addCppMethod('int', '__bool__', '()', "return self->IsOk();") c.addCppCode("""\ #ifdef __WXMAC__ #include <wx/osx/private.h> #endif """) c.addCppMethod( 'void', 'MacSetTheme', '(int macThemeBrushID)', """\ #ifdef __WXMAC__ self->SetColour(wxColour(wxMacCreateCGColorFromHITheme(macThemeBrushID))); #else wxPyRaiseNotImplemented(); #endif """) c.addAutoProperties() # The stock Brush items are documented as simple pointers, but in reality # they are macros that evaluate to a function call that returns a brush # pointer, and that is only valid *after* the wx.App object has been # created. That messes up the code that SIP generates for them, so we need # to come up with another solution. So instead we will just create # uninitialized brush in a block of Python code, that will then be # intialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxBrush* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock brushes will be initialized when the wx.App object is created.\n' for item in module: if '_BRUSH' in item.name: item.ignore() pycode += '%s = Brush()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) # it is delay-initialized, see stockgdi.sip module.find('wxTheBrushList').ignore() # Some aliases that should be phased out eventually, (sooner rather than # later.) They are already gone (or wrapped by an #if) in the C++ code, # and so are not found in the documentation... module.addPyCode("""\ wx.STIPPLE_MASK_OPAQUE = int(wx.BRUSHSTYLE_STIPPLE_MASK_OPAQUE) wx.STIPPLE_MASK = int(wx.BRUSHSTYLE_STIPPLE_MASK) wx.STIPPLE = int(wx.BRUSHSTYLE_STIPPLE) wx.BDIAGONAL_HATCH = int(wx.BRUSHSTYLE_BDIAGONAL_HATCH) wx.CROSSDIAG_HATCH = int(wx.BRUSHSTYLE_CROSSDIAG_HATCH) wx.FDIAGONAL_HATCH = int(wx.BRUSHSTYLE_FDIAGONAL_HATCH) wx.CROSS_HATCH = int(wx.BRUSHSTYLE_CROSS_HATCH) wx.HORIZONTAL_HATCH = int(wx.BRUSHSTYLE_HORIZONTAL_HATCH) wx.VERTICAL_HATCH = int(wx.BRUSHSTYLE_VERTICAL_HATCH) """) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
def findControlImages(elementOrString): """ Given the input `element` (an instance of `xml.etree.ElementTree.Element` or a plain string) representing a Phoenix class description, this function will scan the doxygen image folder ``DOXYROOT`` to look for a widget screenshot. If this class indeed represents a widget and a screenshot is found, it is then copied to the appropriate Sphinx input folder ``WIDGETS_IMAGES_ROOT`` in one of its sub-folders (``wxmsw``, ``wxgtk``, ``wxmac``) depending on which platform the screenshot was taken. :param `elementOrString`: the XML element we want to examine (an instance of xml.etree.ElementTree.Element) or a plain string (usually for wx.lib). :rtype: `list` :returns: A list of image paths, every element of it representing a screenshot on a different platform. An empty list if returned if no screenshots have been found. .. note:: If a screenshot doesn't exist for one (or more) platform but it exists for others, the missing images will be replaced by the "no_appearance.png" file (you can find it inside the ``WIDGETS_IMAGES_ROOT`` folder. """ from etgtools.tweaker_tools import removeWxPrefix if isinstance(elementOrString, string_base): class_name = py_class_name = elementOrString.lower() else: element = elementOrString class_name = element.pyName if element.pyName else removeWxPrefix(element.name) py_class_name = wx2Sphinx(class_name)[1] class_name = class_name.lower() py_class_name = py_class_name.lower() image_folder = os.path.join(DOXYROOT, 'images') appearance = ODict() for sub_folder in ['wxmsw', 'wxmac', 'wxgtk']: png_file = class_name + '.png' appearance[sub_folder] = '' possible_image = os.path.join(image_folder, sub_folder, png_file) new_path = os.path.join(WIDGETS_IMAGES_ROOT, sub_folder) py_png_file = py_class_name + '.png' new_file = os.path.join(new_path, py_png_file) if os.path.isfile(new_file): appearance[sub_folder] = py_png_file elif os.path.isfile(possible_image): if not os.path.isdir(new_path): os.makedirs(new_path) if not os.path.isfile(new_file): shutil.copyfile(possible_image, new_file) appearance[sub_folder] = py_png_file if not any(list(appearance.values())): return [] for sub_folder, image in list(appearance.items()): if not image: appearance[sub_folder] = '../no_appearance.png' return list(appearance.values())
def convertToPython(text): """ Converts the input `text` into a more ReSTified version of it. This involves the following steps: 1. Any C++ specific declaration (like ``unsigned``, ``size_t`` and so on is removed. 2. Lines starting with "Include file" or "#include" are ignored. 3. Uppercase constants (i.e., like ID_ANY, HORIZONTAL and so on) are converted into inline literals (i.e., ``ID_ANY``, ``HORIZONTAL``). 4. The "wx" prefix is removed from all the words in the input `text`. #*** :param string `text`: any string. :rtype: `string` """ from etgtools.tweaker_tools import removeWxPrefix from etgtools.item_module_map import ItemModuleMap newlines = [] unwanted = ['Include file', '#include'] for line in text.splitlines(): newline = [] for remove in unwanted: if remove in line: line = line[0:line.index(remove)] break spacer = ' '*(len(line) - len(line.lstrip())) line = replaceCppItems(line) for word in RE_KEEP_SPACES.split(line): if word == VERSION: newline.append(word) continue newword = word for s in PUNCTUATION: newword = newword.replace(s, "") if newword in VALUE_MAP: word = word.replace(newword, VALUE_MAP[newword]) newline.append(word) continue if newword not in IGNORE and not newword.startswith('wx.'): word = removeWxPrefix(word) newword = removeWxPrefix(newword) if "::" in word and not word.endswith("::"): # Bloody SetCursorEvent... word = word.replace("::wx", ".") # *** word = word.replace("::", ".") word = "`%s`" % word newline.append(word) continue if (newword.upper() == newword and newword not in PUNCTUATION and newword not in IGNORE and len(newword.strip()) > 1 and not isNumeric(newword) and newword not in ['DC', 'GCDC']): if '``' not in newword and '()' not in word and '**' not in word: word = word.replace(newword, "``%s``" % ItemModuleMap().get_fullname(newword)) word = word.replace('->', '.') newline.append(word) newline = spacer + ''.join(newline) newline = newline.replace(':see:', '.. seealso::') newline = newline.replace(':note:', '.. note::') newlines.append(newline) formatted = "\n".join(newlines) formatted = formatted.replace('\\', '\\\\') return formatted
def pythonizeType(ptype, is_param): """ Replaces various C++ specific stuff with more Pythonized version of them, for parameter lists and return types (i.e., the `:param:` and `:rtype:` ReST roles). :param string `ptype`: any string; :param bool `is_param`: ``True`` if this is a parameter description, ``False`` if it is a return type. :rtype: `string` """ from etgtools.tweaker_tools import removeWxPrefix if 'size_t' in ptype: ptype = 'int' elif 'wx.' in ptype: ptype = ptype[3:] else: ptype = wx2Sphinx(replaceCppItems(ptype))[1] ptype = ptype.replace('::', '.').replace('*&', '') ptype = ptype.replace('int const', 'int') ptype = ptype.replace('Uint32', 'int').replace('**', '').replace('Int32', 'int') ptype = ptype.replace('FILE', 'file') ptype = ptype.replace('boolean', 'bool') for item in ['unsignedchar', 'unsignedint', 'unsignedlong', 'unsigned']: ptype = ptype.replace(item, 'int') ptype = ptype.strip() ptype = removeWxPrefix(ptype) if '. wx' in ptype: #*** ptype = ptype.replace('. wx', '.') plower = ptype.lower() if plower == 'double': ptype = 'float' if plower in ['string', 'char', 'artid', 'artclient']: ptype = 'string' if plower in ['coord', 'byte', 'fileoffset', 'short', 'time_t', 'intptr', 'uintptr', 'windowid']: ptype = 'int' if plower in ['longlong']: ptype = 'long' cpp = ['ArrayString', 'ArrayInt', 'ArrayDouble'] python = ['list of strings', 'list of integers', 'list of floats'] for c, p in zip(cpp, python): ptype = ptype.replace(c, p) if 'Image.' in ptype: ptype = ptype.split('.')[-1] if 'FileName' in ptype: ptype = 'string' if ptype.endswith('&'): ptype = ptype[0:-1] if ' ' not in ptype: ptype = ':class:`%s`'%ptype else: if is_param and '.' in ptype: modules = list(MODULENAME_REPLACE.values()) modules.sort() modules = modules[1:] if ptype.split('.')[0] + '.' in modules: ptype = ':ref:`%s`'%ptype return ptype
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('wxImage') assert isinstance(c, etgtools.ClassDef) c.find('wxImage').findOverload('(const char *const *xpmData)').ignore() c.find('GetHandlers').ignore() # TODO c.find('wxImage').findOverload('wxBitmap').mustHaveApp() # Ignore the ctors taking raw data buffers, so we can add in our own # versions that are a little smarter (accept any buffer object, check # the data length, etc.) c.find('wxImage').findOverload( 'int width, int height, unsigned char *data, bool static_data').ignore( ) c.find('wxImage').findOverload( 'const wxSize &sz, unsigned char *data, bool static_data').ignore() c.find('wxImage').findOverload( 'int width, int height, unsigned char *data, unsigned char *alpha, bool static_data' ).ignore() c.find('wxImage').findOverload( 'const wxSize &sz, unsigned char *data, unsigned char *alpha, bool static_data' ).ignore() c.addCppCtor_sip('(int width, int height, wxPyBuffer* data)', doc="Creates an image from RGB data in memory.", body="""\ if (! data->checkSize(width*height*3)) return NULL; void* copy = data->copy(); if (! copy) return NULL; sipCpp = new sipwxImage; sipCpp->Create(width, height, (byte*)copy); """) c.addCppCtor_sip( '(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)', doc="Creates an image from RGB data in memory, plus an alpha channel", body="""\ void* dcopy; void* acopy; if (!data->checkSize(width*height*3) || !alpha->checkSize(width*height)) return NULL; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return NULL; sipCpp = new sipwxImage; sipCpp->Create(width, height, (byte*)dcopy, (byte*)acopy, false); """) c.addCppCtor_sip('(const wxSize& size, wxPyBuffer* data)', doc="Creates an image from RGB data in memory.", body="""\ if (! data->checkSize(size->x*size->y*3)) return NULL; void* copy = data->copy(); if (! copy) return NULL; sipCpp = new sipwxImage; sipCpp->Create(size->x, size->y, (byte*)copy, false); """) c.addCppCtor_sip( '(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)', doc="Creates an image from RGB data in memory, plus an alpha channel", body="""\ void* dcopy; void* acopy; if (!data->checkSize(size->x*size->y*3) || !alpha->checkSize(size->x*size->y)) return NULL; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return NULL; sipCpp = new sipwxImage; sipCpp->Create(size->x, size->y, (byte*)dcopy, (byte*)acopy, false); """) # Do the same for the Create method overloads that need to deal with data buffers c.find('Create').findOverload( 'int width, int height, unsigned char *data, bool static_data').ignore( ) c.find('Create').findOverload( 'const wxSize &sz, unsigned char *data, bool static_data').ignore() c.find('Create').findOverload( 'int width, int height, unsigned char *data, unsigned char *alpha, bool static_data' ).ignore() c.find('Create').findOverload( 'const wxSize &sz, unsigned char *data, unsigned char *alpha, bool static_data' ).ignore() c.addCppMethod( 'bool', 'Create', '(int width, int height, wxPyBuffer* data)', doc="Create a new image initialized with the given RGB data.", body="""\ if (! data->checkSize(width*height*3)) return false; void* copy = data->copy(); if (! copy) return false; return self->Create(width, height, (byte*)copy); """) c.addCppMethod( 'bool', 'Create', '(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)', doc= "Create a new image initialized with the given RGB data and Alpha data.", body="""\ void* dcopy; void* acopy; if (!data->checkSize(width*height*3) || !alpha->checkSize(width*height)) return false; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return false; return self->Create(width, height, (byte*)dcopy, (byte*)acopy); """) c.addCppMethod( 'bool', 'Create', '(const wxSize& size, wxPyBuffer* data)', doc="Create a new image initialized with the given RGB data.", body="""\ if (! data->checkSize(size->x*size->y*3)) return false; void* copy = data->copy(); if (! copy) return false; return self->Create(size->x, size->y, (byte*)copy); """) c.addCppMethod( 'bool', 'Create', '(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)', doc= "Create a new image initialized with the given RGB data and Alpha data.", body="""\ void* dcopy; void* acopy; if (!data->checkSize(size->x*size->y*3) || !alpha->checkSize(size->x*size->y)) return false; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return false; return self->Create(size->x, size->y, (byte*)dcopy, (byte*)acopy); """) # And also do similar for SetData and SetAlpha m = c.find('SetData').findOverload('unsigned char *data') bd, dd = m.briefDoc, m.detailedDoc m.ignore() c.addCppMethod('void', 'SetData', '(wxPyBuffer* data)', briefDoc=bd, detailedDoc=dd, body="""\ if (!data->checkSize(self->GetWidth()*self->GetHeight()*3)) return; void* copy = data->copy(); if (!copy) return; self->SetData((byte*)copy, false); """) c.find('SetData').findOverload('int new_width').ignore() c.addCppMethod('void', 'SetData', '(wxPyBuffer* data, int new_width, int new_height)', body="""\ if (!data->checkSize(new_width*new_height*3)) return; void* copy = data->copy(); if (!copy) return; self->SetData((byte*)copy, new_width, new_height, false); """) m = c.find('SetAlpha').findOverload('unsigned char *alpha') bd, dd = m.briefDoc, m.detailedDoc m.ignore() c.addCppMethod('void', 'SetAlpha', '(wxPyBuffer* alpha)', briefDoc=bd, detailedDoc=dd, body="""\ if (!alpha->checkSize(self->GetWidth()*self->GetHeight())) return; void* copy = alpha->copy(); if (!copy) return; self->SetAlpha((byte*)copy, false); """) # GetData() and GetAlpha() return a copy of the image data/alpha bytes as # a bytearray object. c.find('GetData').ignore() c.addCppMethod('PyObject*', 'GetData', '()', doc="Returns a copy of the RGB bytes of the image.", body="""\ byte* data = self->GetData(); Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3; PyObject* rv = NULL; wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len)); return rv; """) c.find('GetAlpha').findOverload('()').ignore() c.addCppMethod('PyObject*', 'GetAlpha', '()', doc="Returns a copy of the Alpha bytes of the image.", body="""\ byte* data = self->GetAlpha(); Py_ssize_t len = self->GetWidth() * self->GetHeight(); PyObject* rv = NULL; wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len)); return rv; """) # GetDataBuffer, GetAlphaBuffer provide direct access to the image's # internal buffers as a writable buffer object. We'll use memoryview # objects. c.addCppMethod('PyObject*', 'GetDataBuffer', '()', doc="""\ Returns a writable Python buffer object that is pointing at the RGB image data buffer inside the :class:`Image`. You need to ensure that you do not use this buffer object after the image has been destroyed.""", body="""\ byte* data = self->GetData(); Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3; PyObject* rv; wxPyThreadBlocker blocker; rv = wxPyMakeBuffer(data, len); return rv; """) c.addCppMethod('PyObject*', 'GetAlphaBuffer', '()', doc="""\ Returns a writable Python buffer object that is pointing at the Alpha data buffer inside the :class:`Image`. You need to ensure that you do not use this buffer object after the image has been destroyed.""", body="""\ byte* data = self->GetAlpha(); Py_ssize_t len = self->GetWidth() * self->GetHeight(); PyObject* rv; wxPyThreadBlocker blocker; rv = wxPyMakeBuffer(data, len); return rv; """) # SetDataBuffer, SetAlphaBuffer tell the image to use some other memory # buffer pointed to by a Python buffer object. c.addCppMethod('void', 'SetDataBuffer', '(wxPyBuffer* data)', doc="""\ Sets the internal image data pointer to point at a Python buffer object. This can save making an extra copy of the data but you must ensure that the buffer object lives lives at least as long as the :class:`Image` does.""", body="""\ if (!data->checkSize(self->GetWidth() * self->GetHeight() * 3)) return; // True means don't free() the pointer self->SetData((byte*)data->m_ptr, true); """) c.addCppMethod('void', 'SetDataBuffer', '(wxPyBuffer* data, int new_width, int new_height)', doc="""\ Sets the internal image data pointer to point at a Python buffer object. This can save making an extra copy of the data but you must ensure that the buffer object lives lives at least as long as the :class:`Image` does.""", body="""\ if (!data->checkSize(new_width * new_height * 3)) return; // True means don't free() the pointer self->SetData((byte*)data->m_ptr, new_width, new_height, true); """) c.addCppMethod('void', 'SetAlphaBuffer', '(wxPyBuffer* alpha)', doc="""\ Sets the internal image alpha pointer to point at a Python buffer object. This can save making an extra copy of the data but you must ensure that the buffer object lives lives at least as long as the :class:`Image` does.""", body="""\ if (!alpha->checkSize(self->GetWidth() * self->GetHeight())) return; // True means don't free() the pointer self->SetAlpha((byte*)alpha->m_ptr, true); """) def setParamsPyInt(name): """Set the pyInt flag on 'unsigned char' params""" method = c.find(name) for m in [method] + method.overloads: for p in m.items: if p.type == 'unsigned char': p.pyInt = True setParamsPyInt('Replace') setParamsPyInt('ConvertAlphaToMask') setParamsPyInt('ConvertToMono') setParamsPyInt('ConvertToDisabled') setParamsPyInt('IsTransparent') setParamsPyInt('SetAlpha') setParamsPyInt('SetMaskColour') setParamsPyInt('SetMaskFromImage') setParamsPyInt('SetRGB') c.find('FindFirstUnusedColour').type = 'void' c.find('FindFirstUnusedColour.r').pyInt = True c.find('FindFirstUnusedColour.g').pyInt = True c.find('FindFirstUnusedColour.b').pyInt = True c.find('FindFirstUnusedColour.startR').pyInt = True c.find('FindFirstUnusedColour.startG').pyInt = True c.find('FindFirstUnusedColour.startB').pyInt = True c.find('FindFirstUnusedColour.r').out = True c.find('FindFirstUnusedColour.g').out = True c.find('FindFirstUnusedColour.b').out = True c.find('GetAlpha').findOverload('int x, int y').pyInt = True c.find('GetRed').pyInt = True c.find('GetGreen').pyInt = True c.find('GetBlue').pyInt = True c.find('GetMaskRed').pyInt = True c.find('GetMaskGreen').pyInt = True c.find('GetMaskBlue').pyInt = True c.find('GetOrFindMaskColour').type = 'void' c.find('GetOrFindMaskColour.r').pyInt = True c.find('GetOrFindMaskColour.g').pyInt = True c.find('GetOrFindMaskColour.b').pyInt = True c.find('GetOrFindMaskColour.r').out = True c.find('GetOrFindMaskColour.g').out = True c.find('GetOrFindMaskColour.b').out = True c.find('RGBValue.red').pyInt = True c.find('RGBValue.green').pyInt = True c.find('RGBValue.blue').pyInt = True c.find('RGBValue.RGBValue.r').pyInt = True c.find('RGBValue.RGBValue.g').pyInt = True c.find('RGBValue.RGBValue.b').pyInt = True c.addCppMethod('int', '__nonzero__', '()', 'return self->IsOk();') c.addPyMethod('ConvertToBitmap', '(self, depth=-1)', doc="""\ ConvertToBitmap(depth=-1) -> Bitmap\n Convert the image to a :class:`wx.Bitmap`.""", body="""\ bmp = wx.Bitmap(self, depth) return bmp """) c.addPyMethod('ConvertToMonoBitmap', '(self, red, green, blue)', doc="""\ ConvertToMonoBitmap(red, green, blue) -> Bitmap\n Creates a monochrome version of the image and returns it as a :class:`wx.Bitmap`.""", body="""\ mono = self.ConvertToMono( red, green, blue ) bmp = wx.Bitmap( mono, 1 ) return bmp """) c.addCppMethod( 'wxImage*', 'AdjustChannels', '(double factor_red, double factor_green, double factor_blue, double factor_alpha=1.0)', doc="""\ This function muliplies all 4 channels (red, green, blue, alpha) with a factor (around 1.0). Useful for gamma correction, colour correction and to add a certain amount of transparency to a image (fade in fade out effects). If factor_alpha is given but the original image has no alpha channel then a alpha channel will be added. """, body="""\ wxCHECK_MSG( self->Ok(), NULL, wxT("invalid image") ); wxImage* dest = new wxImage( self->GetWidth(), self->GetHeight(), false ); wxCHECK_MSG( dest && dest->IsOk(), NULL, wxT("unable to create image") ); unsigned rgblen = 3 * self->GetWidth() * self->GetHeight(); unsigned alphalen = self->GetWidth() * self->GetHeight(); byte* src_data = self->GetData(); byte* src_alpha = self->GetAlpha(); byte* dst_data = dest->GetData(); byte* dst_alpha = NULL; // adjust rgb if ( factor_red == 1.0 && factor_green == 1.0 && factor_blue == 1.0) { // nothing to do for RGB memcpy(dst_data, src_data, rgblen); } else { // rgb pixel for pixel for ( unsigned i = 0; i < rgblen; i= i + 3 ) { dst_data[i] = (byte) wxMin( 255, (int) (factor_red * src_data[i]) ); dst_data[i + 1] = (byte) wxMin( 255, (int) (factor_green * src_data[i + 1]) ); dst_data[i + 2] = (byte) wxMin( 255, (int) (factor_blue * src_data[i + 2]) ); } } // adjust the mask colour if ( self->HasMask() ) { dest->SetMaskColour((byte) wxMin( 255, (int) (factor_red * self->GetMaskRed() ) ), (byte) wxMin( 255, (int) (factor_green * self->GetMaskGreen() ) ), (byte) wxMin( 255, (int) (factor_blue * self->GetMaskBlue() ) ) ); } // adjust the alpha channel if ( src_alpha ) { // source image already has alpha information dest->SetAlpha(); // create an empty alpha channel (not initialized) dst_alpha = dest->GetAlpha(); wxCHECK_MSG( dst_alpha, NULL, wxT("unable to create alpha data") ); if ( factor_alpha == 1.0) { // no need to adjust memcpy(dst_alpha, src_alpha, alphalen); } else { // alpha value for alpha value for ( unsigned i = 0; i < alphalen; ++i ) { dst_alpha[i] = (byte) wxMin( 255, (int) (factor_alpha * src_alpha[i]) ); } } } else if ( factor_alpha != 1.0 ) { // no alpha yet but we want to adjust -> create dest->SetAlpha(); // create an empty alpha channel (not initialized) dst_alpha = dest->GetAlpha(); wxCHECK_MSG( dst_alpha, NULL, wxT("unable to create alpha data") ); for ( unsigned i = 0; i < alphalen; ++i ) { dst_alpha[i] = (byte) wxMin( 255, (int) (factor_alpha * 255) ); } } // do we have an alpha channel and a mask in the new image? if ( dst_alpha && dest->HasMask() ) { // make the mask transparent honoring the alpha channel const byte mr = dest->GetMaskRed(); const byte mg = dest->GetMaskGreen(); const byte mb = dest->GetMaskBlue(); for ( unsigned i = 0; i < alphalen; ++i ) { int n = i * 3; dst_alpha[i] = ( dst_data[n] == mr && dst_data[n + 1] == mg && dst_data[n + 2] == mb ) ? wxIMAGE_ALPHA_TRANSPARENT : dst_alpha[i]; } // remove the mask now dest->SetMask(false); } return dest;""", factory=True) c.addProperty('Width GetWidth') c.addProperty('Height GetHeight') c.addProperty('MaskBlue GetMaskBlue') c.addProperty('MaskGreen GetMaskGreen') c.addProperty('MaskRed GetMaskRed') c.addProperty('Type GetType SetType') # For compatibility: module.addPyFunction( 'EmptyImage', '(width=0, height=0, clear=True)', deprecated="Use :class:`Image` instead.", doc= 'A compatibility wrapper for the wx.Image(width, height) constructor', body='return Image(width, height, clear)') module.addPyFunction( 'ImageFromBitmap', '(bitmap)', deprecated="Use bitmap.ConvertToImage instead.", doc='Create a :class:`Image` from a :class:`wx.Bitmap`', body='return bitmap.ConvertToImage()') module.addPyFunction('ImageFromStream', '(stream, type=BITMAP_TYPE_ANY, index=-1)', deprecated="Use :class:`Image` instead.", doc='Load an image from a stream (file-like object)', body='return wx.Image(stream, type, index)') module.addPyFunction( 'ImageFromData', '(width, height, data)', deprecated="Use :class:`Image` instead.", doc='Compatibility wrapper for creating an image from RGB data', body='return Image(width, height, data)') module.addPyFunction( 'ImageFromDataWithAlpha', '(width, height, data, alpha)', deprecated="Use :class:`Image` instead.", doc= 'Compatibility wrapper for creating an image from RGB and Alpha data', body='return Image(width, height, data, alpha)') module.addPyFunction('ImageFromBuffer', '(width, height, dataBuffer, alphaBuffer=None)', doc="""\ Creates a :class:`Image` from the data in `dataBuffer`. The `dataBuffer` parameter must be a Python object that implements the buffer interface, such as a string, array, etc. The `dataBuffer` object is expected to contain a series of RGB bytes and be width*height*3 bytes long. A buffer object can optionally be supplied for the image's alpha channel data, and it is expected to be width*height bytes long. The :class:`Image` will be created with its data and alpha pointers initialized to the memory address pointed to by the buffer objects, thus saving the time needed to copy the image data from the buffer object to the :class:`Image`. While this has advantages, it also has the shoot-yourself-in-the-foot risks associated with sharing a C pointer between two objects. To help alleviate the risk a reference to the data and alpha buffer objects are kept with the :class:`Image`, so that they won't get deleted until after the wx.Image is deleted. However please be aware that it is not guaranteed that an object won't move its memory buffer to a new location when it needs to resize its contents. If that happens then the :class:`Image` will end up referring to an invalid memory location and could cause the application to crash. Therefore care should be taken to not manipulate the objects used for the data and alpha buffers in a way that would cause them to change size. """, body="""\ img = Image(width, height) img.SetDataBuffer(dataBuffer) if alphaBuffer: img.SetAlphaBuffer(alphaBuffer) img._buffer = dataBuffer img._alpha = alphaBuffer return img """) #------------------------------------------------------- c = module.find('wxImageHistogram') c.bases = [] # wxImageHistogramBase doesn't actually exist setParamsPyInt('MakeKey') c.find('FindFirstUnusedColour').type = 'void' c.find('FindFirstUnusedColour.r').pyInt = True c.find('FindFirstUnusedColour.g').pyInt = True c.find('FindFirstUnusedColour.b').pyInt = True c.find('FindFirstUnusedColour.startR').pyInt = True c.find('FindFirstUnusedColour.startG').pyInt = True c.find('FindFirstUnusedColour.startB').pyInt = True c.find('FindFirstUnusedColour.r').out = True c.find('FindFirstUnusedColour.g').out = True c.find('FindFirstUnusedColour.b').out = True #------------------------------------------------------- c = module.find('wxImageHandler') c.addPrivateCopyCtor() c.find('GetLibraryVersionInfo').ignore() c.find('DoGetImageCount').ignore(False) c.find('DoCanRead').ignore(False) #------------------------------------------------------- module.find('wxIMAGE_ALPHA_TRANSPARENT').pyInt = True module.find('wxIMAGE_ALPHA_OPAQUE').pyInt = True module.find('wxIMAGE_ALPHA_THRESHOLD').pyInt = True # These are defines for string objects, not integers, so we can't # generate code for them the same way as integer values. Since they are # #defines we can't just tell SIP that they are global wxString objects # because it will then end up taking the address of temporary values when # it makes the getters for them. So instead we'll just make some python # code to insert into the .py module and hope that the interface file # always has the correct values of these options. pycode = "" for item in module: if 'IMAGE_OPTION' in item.name and isinstance(item, etgtools.DefineDef): item.ignore() name = tools.removeWxPrefix(item.name) value = item.value for txt in ['wxString(', 'wxT(', ')']: value = value.replace(txt, '') pycode += '%s = %s\n' % (name, value) module.addPyCode(pycode) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
def findControlImages(elementOrString): """ Given the input `element` (an instance of `xml.etree.ElementTree.Element` or a plain string) representing a Phoenix class description, this function will scan the doxygen image folder ``DOXYROOT`` to look for a widget screenshot. If this class indeed represents a widget and a screenshot is found, it is then copied to the appropriate Sphinx input folder ``WIDGETS_IMAGES_ROOT`` in one of its sub-folders (``wxmsw``, ``wxgtk``, ``wxmac``) depending on which platform the screenshot was taken. :param `elementOrString`: the XML element we want to examine (an instance of xml.etree.ElementTree.Element) or a plain string (usually for wx.lib). :rtype: `list` :returns: A list of image paths, every element of it representing a screenshot on a different platform. An empty list if returned if no screenshots have been found. .. note:: If a screenshot doesn't exist for one (or more) platform but it exists for others, the missing images will be replaced by the "no_appearance.png" file (you can find it inside the ``WIDGETS_IMAGES_ROOT`` folder. """ from etgtools.tweaker_tools import removeWxPrefix if isinstance(elementOrString, string_base): class_name = py_class_name = elementOrString.lower() else: element = elementOrString class_name = element.pyName if element.pyName else removeWxPrefix( element.name) py_class_name = wx2Sphinx(class_name)[1] class_name = class_name.lower() py_class_name = py_class_name.lower() image_folder = os.path.join(DOXYROOT, 'images') appearance = ODict() for sub_folder in ['wxmsw', 'wxmac', 'wxgtk']: png_file = class_name + '.png' appearance[sub_folder] = '' possible_image = os.path.join(image_folder, sub_folder, png_file) new_path = os.path.join(WIDGETS_IMAGES_ROOT, sub_folder) py_png_file = py_class_name + '.png' new_file = os.path.join(new_path, py_png_file) if os.path.isfile(new_file): appearance[sub_folder] = py_png_file elif os.path.isfile(possible_image): if not os.path.isdir(new_path): os.makedirs(new_path) if not os.path.isfile(new_file): shutil.copyfile(possible_image, new_file) appearance[sub_folder] = py_png_file if not any(list(appearance.values())): return [] for sub_folder, image in list(appearance.items()): if not image: appearance[sub_folder] = '../no_appearance.png' return list(appearance.values())
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('wxBrush') assert isinstance(c, etgtools.ClassDef) tools.removeVirtuals(c) # Set mustHaveApp on all ctors except the default ctor for ctor in c.find('wxBrush').all(): if ctor.isCtor and ctor.argsString != '()': ctor.mustHaveApp() c.addCppMethod('int', '__nonzero__', '()', """\ return self->IsOk(); """) c.addCppCode("""\ #ifdef __WXMAC__ #include <wx/osx/private.h> #endif """) c.addCppMethod('void', 'MacSetTheme', '(int macThemeBrushID)', """\ #ifdef __WXMAC__ self->SetColour(wxColour(wxMacCreateCGColorFromHITheme(macThemeBrushID))); #else wxPyRaiseNotImplemented(); #endif """) c.addAutoProperties() # The stock Brush items are documented as simple pointers, but in reality # they are macros that evaluate to a function call that returns a brush # pointer, and that is only valid *after* the wx.App object has been # created. That messes up the code that SIP generates for them, so we need # to come up with another solution. So instead we will just create # uninitialized brush in a block of Python code, that will then be # intialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxBrush* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock brushes will be initialized when the wx.App object is created.\n' for item in module: if '_BRUSH' in item.name: item.ignore() pycode += '%s = Brush()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) # it is delay-initialized, see stockgdi.sip module.find('wxTheBrushList').ignore() # Some aliases that should be phased out eventually, (sooner rather than # later.) They are already gone (or wrapped by an #if) in the C++ code, # and so are not found in the documentation... module.addPyCode("""\ wx.STIPPLE_MASK_OPAQUE = int(wx.BRUSHSTYLE_STIPPLE_MASK_OPAQUE) wx.STIPPLE_MASK = int(wx.BRUSHSTYLE_STIPPLE_MASK) wx.STIPPLE = int(wx.BRUSHSTYLE_STIPPLE) wx.BDIAGONAL_HATCH = int(wx.BRUSHSTYLE_BDIAGONAL_HATCH) wx.CROSSDIAG_HATCH = int(wx.BRUSHSTYLE_CROSSDIAG_HATCH) wx.FDIAGONAL_HATCH = int(wx.BRUSHSTYLE_FDIAGONAL_HATCH) wx.CROSS_HATCH = int(wx.BRUSHSTYLE_CROSS_HATCH) wx.HORIZONTAL_HATCH = int(wx.BRUSHSTYLE_HORIZONTAL_HATCH) wx.VERTICAL_HATCH = int(wx.BRUSHSTYLE_VERTICAL_HATCH) """) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
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('wxPen') assert isinstance(c, etgtools.ClassDef) tools.removeVirtuals(c) # The stipple bitmap ctor is not implemented on wxGTK c.find('wxPen').findOverload('wxBitmap').ignore() m = c.find('GetDashes') assert isinstance(m, etgtools.MethodDef) m.find('dashes').ignore() m.type = 'wxArrayInt*' m.factory = True m.setCppCode("""\ wxArrayInt* arr = new wxArrayInt; wxDash* dashes; int num = self->GetDashes(&dashes); for (int i=0; i<num; i++) arr->Add(dashes[i]); return arr; """) # SetDashes does not take ownership of the array passed to it, yet that # array must be kept alive as long as the pen lives, so we'll create an # array holder object that will be associated with the pen, and that will # delete the dashes array when it is deleted. #c.find('SetDashes').ignore() c.addHeaderCode('#include "arrayholder.h"') m = c.find('SetDashes') # ignore the existing parameters m.find('n').ignore() m.find('dash').ignore() # add a new one m.items.append(etgtools.ParamDef(type='const wxArrayInt&', name='dashes')) m.setCppCode_sip("""\ size_t len = dashes->GetCount(); wxDashCArrayHolder* holder = new wxDashCArrayHolder; holder->m_array = new wxDash[len]; for (int idx=0; idx<len; idx+=1) { holder->m_array[idx] = (*dashes)[idx]; } // Make a PyObject for the holder, and transfer its ownership to self. PyObject* pyHolder = sipConvertFromNewType( (void*)holder, sipType_wxDashCArrayHolder, (PyObject*)sipSelf); Py_DECREF(pyHolder); sipCpp->SetDashes(len, holder->m_array); """) c.addAutoProperties() # The stock Pen items are documented as simple pointers, but in reality # they are macros that evaluate to a function call that returns a pen # pointer, and that is only valid *after* the wx.App object has been # created. That messes up the code that SIP generates for them, so we need # to come up with another solution. So instead we will just create # uninitialized pens in a block of Python code, that will then be # intialized later when the wx.App is created. c.addCppMethod('void', '_copyFrom', '(const wxPen* other)', "*self = *other;", briefDoc="For internal use only.") # ?? pycode = '# These stock pens will be initialized when the wx.App object is created.\n' for item in module: if '_PEN' in item.name: item.ignore() pycode += '%s = Pen()\n' % tools.removeWxPrefix(item.name) module.addPyCode(pycode) # it is delay-initialized, see stockgdi.sip module.find('wxThePenList').ignore() # Some aliases that should be phased out eventually, (sooner rather than # later.) They are already gone (or wrapped by an #if) in the C++ code, # and so are not found in the documentation... module.addPyCode("""\ wx.SOLID = int(wx.PENSTYLE_SOLID) wx.DOT = int(wx.PENSTYLE_DOT) wx.LONG_DASH = int(wx.PENSTYLE_LONG_DASH) wx.SHORT_DASH = int(wx.PENSTYLE_SHORT_DASH) wx.DOT_DASH = int(wx.PENSTYLE_DOT_DASH) wx.USER_DASH = int(wx.PENSTYLE_USER_DASH) wx.TRANSPARENT = int(wx.PENSTYLE_TRANSPARENT) """) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)
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('wxImage') assert isinstance(c, etgtools.ClassDef) c.find('wxImage').findOverload('(const char *const *xpmData)').ignore() c.find('GetHandlers').ignore() # TODO # Ignore the ctors taking raw data buffers, so we can add in our own # versions that are a little smarter (accept any buffer object, check # the data length, etc.) c.find('wxImage').findOverload('int width, int height, unsigned char *data, bool static_data').ignore() c.find('wxImage').findOverload('const wxSize &sz, unsigned char *data, bool static_data').ignore() c.find('wxImage').findOverload('int width, int height, unsigned char *data, unsigned char *alpha, bool static_data').ignore() c.find('wxImage').findOverload('const wxSize &sz, unsigned char *data, unsigned char *alpha, bool static_data').ignore() c.addCppCtor_sip('(int width, int height, wxPyBuffer* data)', doc="Creates an image from RGB data in memory.", body="""\ if (! data->checkSize(width*height*3)) return NULL; void* copy = data->copy(); if (! copy) return NULL; sipCpp = new sipwxImage; sipCpp->Create(width, height, (byte*)copy); """) c.addCppCtor_sip('(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)', doc="Creates an image from RGB data in memory, plus an alpha channel", body="""\ void* dcopy; void* acopy; if (!data->checkSize(width*height*3) || !alpha->checkSize(width*height)) return NULL; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return NULL; sipCpp = new sipwxImage; sipCpp->Create(width, height, (byte*)dcopy, (byte*)acopy, false); """) c.addCppCtor_sip('(const wxSize& size, wxPyBuffer* data)', doc="Creates an image from RGB data in memory.", body="""\ if (! data->checkSize(size->x*size->y*3)) return NULL; void* copy = data->copy(); if (! copy) return NULL; sipCpp = new sipwxImage; sipCpp->Create(size->x, size->y, (byte*)copy, false); """) c.addCppCtor_sip('(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)', doc="Creates an image from RGB data in memory, plus an alpha channel", body="""\ void* dcopy; void* acopy; if (!data->checkSize(size->x*size->y*3) || !alpha->checkSize(size->x*size->y)) return NULL; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return NULL; sipCpp = new sipwxImage; sipCpp->Create(size->x, size->y, (byte*)dcopy, (byte*)acopy, false); """) # Do the same for the Create method overloads that need to deal with data buffers c.find('Create').findOverload('int width, int height, unsigned char *data, bool static_data').ignore() c.find('Create').findOverload('const wxSize &sz, unsigned char *data, bool static_data').ignore() c.find('Create').findOverload('int width, int height, unsigned char *data, unsigned char *alpha, bool static_data').ignore() c.find('Create').findOverload('const wxSize &sz, unsigned char *data, unsigned char *alpha, bool static_data').ignore() c.addCppMethod('bool', 'Create', '(int width, int height, wxPyBuffer* data)', doc="Create a new image initialized with the given RGB data.", body="""\ if (! data->checkSize(width*height*3)) return false; void* copy = data->copy(); if (! copy) return false; return self->Create(width, height, (byte*)copy); """) c.addCppMethod('bool', 'Create', '(int width, int height, wxPyBuffer* data, wxPyBuffer* alpha)', doc="Create a new image initialized with the given RGB data and Alpha data.", body="""\ void* dcopy; void* acopy; if (!data->checkSize(width*height*3) || !alpha->checkSize(width*height)) return false; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return false; return self->Create(width, height, (byte*)dcopy, (byte*)acopy); """) c.addCppMethod('bool', 'Create', '(const wxSize& size, wxPyBuffer* data)', doc="Create a new image initialized with the given RGB data.", body="""\ if (! data->checkSize(size->x*size->y*3)) return false; void* copy = data->copy(); if (! copy) return false; return self->Create(size->x, size->y, (byte*)copy); """) c.addCppMethod('bool', 'Create', '(const wxSize& size, wxPyBuffer* data, wxPyBuffer* alpha)', doc="Create a new image initialized with the given RGB data and Alpha data.", body="""\ void* dcopy; void* acopy; if (!data->checkSize(size->x*size->y*3) || !alpha->checkSize(size->x*size->y)) return false; if ((dcopy = data->copy()) == NULL || (acopy = alpha->copy()) == NULL) return false; return self->Create(size->x, size->y, (byte*)dcopy, (byte*)acopy); """) # And also do similar for SetData and SetAlpha m = c.find('SetData').findOverload('unsigned char *data') bd, dd = m.briefDoc, m.detailedDoc m.ignore() c.addCppMethod('void', 'SetData', '(wxPyBuffer* data)', briefDoc=bd, detailedDoc=dd, body="""\ if (!data->checkSize(self->GetWidth()*self->GetHeight()*3)) return; void* copy = data->copy(); if (!copy) return; self->SetData((byte*)copy, false); """) c.find('SetData').findOverload('int new_width').ignore() c.addCppMethod('void', 'SetData', '(wxPyBuffer* data, int new_width, int new_height)', body="""\ if (!data->checkSize(new_width*new_height*3)) return; void* copy = data->copy(); if (!copy) return; self->SetData((byte*)copy, new_width, new_height, false); """) m = c.find('SetAlpha').findOverload('unsigned char *alpha') bd, dd = m.briefDoc, m.detailedDoc m.ignore() c.addCppMethod('void', 'SetAlpha', '(wxPyBuffer* alpha)', briefDoc=bd, detailedDoc=dd, body="""\ if (!alpha->checkSize(self->GetWidth()*self->GetHeight())) return; void* copy = alpha->copy(); if (!copy) return; self->SetAlpha((byte*)copy, false); """) # GetData() and GetAlpha() return a copy of the image data/alpha bytes as # a bytearray object. c.find('GetData').ignore() c.addCppMethod('PyObject*', 'GetData', '()', doc="Returns a copy of the RGB bytes of the image.", body="""\ byte* data = self->GetData(); Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3; PyObject* rv = NULL; wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len)); return rv; """) c.find('GetAlpha').findOverload('()').ignore() c.addCppMethod('PyObject*', 'GetAlpha', '()', doc="Returns a copy of the Alpha bytes of the image.", body="""\ byte* data = self->GetAlpha(); Py_ssize_t len = self->GetWidth() * self->GetHeight(); PyObject* rv = NULL; wxPyBLOCK_THREADS( rv = PyByteArray_FromStringAndSize((const char*)data, len)); return rv; """) # GetDataBuffer, GetAlphaBuffer provide direct access to the image's # internal buffers as a writable buffer object. We'll use memoryview # objects. c.addCppMethod('PyObject*', 'GetDataBuffer', '()', doc="""\ Returns a writable Python buffer object that is pointing at the RGB image data buffer inside the :class:`Image`. You need to ensure that you do not use this buffer object after the image has been destroyed.""", body="""\ byte* data = self->GetData(); Py_ssize_t len = self->GetWidth() * self->GetHeight() * 3; PyObject* rv; wxPyThreadBlocker blocker; rv = wxPyMakeBuffer(data, len); return rv; """) c.addCppMethod('PyObject*', 'GetAlphaBuffer', '()', doc="""\ Returns a writable Python buffer object that is pointing at the Alpha data buffer inside the :class:`Image`. You need to ensure that you do not use this buffer object after the image has been destroyed.""", body="""\ byte* data = self->GetAlpha(); Py_ssize_t len = self->GetWidth() * self->GetHeight(); PyObject* rv; wxPyThreadBlocker blocker; rv = wxPyMakeBuffer(data, len); return rv; """) # SetDataBuffer, SetAlphaBuffer tell the image to use some other memory # buffer pointed to by a Python buffer object. c.addCppMethod('void', 'SetDataBuffer', '(wxPyBuffer* data)', doc="""\ Sets the internal image data pointer to point at a Python buffer object. This can save making an extra copy of the data but you must ensure that the buffer object lives lives at least as long as the :class:`Image` does.""", body="""\ if (!data->checkSize(self->GetWidth() * self->GetHeight() * 3)) return; // True means don't free() the pointer self->SetData((byte*)data->m_ptr, true); """) c.addCppMethod('void', 'SetDataBuffer', '(wxPyBuffer* data, int new_width, int new_height)', doc="""\ Sets the internal image data pointer to point at a Python buffer object. This can save making an extra copy of the data but you must ensure that the buffer object lives lives at least as long as the :class:`Image` does.""", body="""\ if (!data->checkSize(new_width * new_height * 3)) return; // True means don't free() the pointer self->SetData((byte*)data->m_ptr, new_width, new_height, true); """) c.addCppMethod('void', 'SetAlphaBuffer', '(wxPyBuffer* alpha)', doc="""\ Sets the internal image alpha pointer to point at a Python buffer object. This can save making an extra copy of the data but you must ensure that the buffer object lives lives at least as long as the :class:`Image` does.""", body="""\ if (!alpha->checkSize(self->GetWidth() * self->GetHeight())) return; // True means don't free() the pointer self->SetAlpha((byte*)alpha->m_ptr, true); """) def setParamsPyInt(name): """Set the pyInt flag on 'unsigned char' params""" method = c.find(name) for m in [method] + method.overloads: for p in m.items: if p.type == 'unsigned char': p.pyInt = True setParamsPyInt('Replace') setParamsPyInt('ConvertAlphaToMask') setParamsPyInt('ConvertToMono') setParamsPyInt('ConvertToDisabled') setParamsPyInt('IsTransparent') setParamsPyInt('SetAlpha') setParamsPyInt('SetMaskColour') setParamsPyInt('SetMaskFromImage') setParamsPyInt('SetRGB') c.find('FindFirstUnusedColour').type = 'void' c.find('FindFirstUnusedColour.r').pyInt = True c.find('FindFirstUnusedColour.g').pyInt = True c.find('FindFirstUnusedColour.b').pyInt = True c.find('FindFirstUnusedColour.startR').pyInt = True c.find('FindFirstUnusedColour.startG').pyInt = True c.find('FindFirstUnusedColour.startB').pyInt = True c.find('FindFirstUnusedColour.r').out = True c.find('FindFirstUnusedColour.g').out = True c.find('FindFirstUnusedColour.b').out = True c.find('GetAlpha').findOverload('int x, int y').pyInt = True c.find('GetRed').pyInt = True c.find('GetGreen').pyInt = True c.find('GetBlue').pyInt = True c.find('GetMaskRed').pyInt = True c.find('GetMaskGreen').pyInt = True c.find('GetMaskBlue').pyInt = True c.find('GetOrFindMaskColour').type = 'void' c.find('GetOrFindMaskColour.r').pyInt = True c.find('GetOrFindMaskColour.g').pyInt = True c.find('GetOrFindMaskColour.b').pyInt = True c.find('GetOrFindMaskColour.r').out = True c.find('GetOrFindMaskColour.g').out = True c.find('GetOrFindMaskColour.b').out = True c.find('RGBValue.red').pyInt = True c.find('RGBValue.green').pyInt = True c.find('RGBValue.blue').pyInt = True c.find('RGBValue.RGBValue.r').pyInt = True c.find('RGBValue.RGBValue.g').pyInt = True c.find('RGBValue.RGBValue.b').pyInt = True c.addCppMethod('int', '__nonzero__', '()', 'return self->IsOk();') c.addPyMethod('ConvertToBitmap', '(self, depth=-1)', doc="""\ ConvertToBitmap(depth=-1) -> Bitmap\n Convert the image to a :class:`wx.Bitmap`.""", body="""\ bmp = wx.Bitmap(self, depth) return bmp """) c.addPyMethod('ConvertToMonoBitmap', '(self, red, green, blue)', doc="""\ ConvertToMonoBitmap(red, green, blue) -> Bitmap\n Creates a monochrome version of the image and returns it as a :class:`wx.Bitmap`.""", body="""\ mono = self.ConvertToMono( red, green, blue ) bmp = wx.Bitmap( mono, 1 ) return bmp """) c.addCppMethod('wxImage*', 'AdjustChannels', '(double factor_red, double factor_green, double factor_blue, double factor_alpha=1.0)', doc="""\ This function muliplies all 4 channels (red, green, blue, alpha) with a factor (around 1.0). Useful for gamma correction, colour correction and to add a certain amount of transparency to a image (fade in fade out effects). If factor_alpha is given but the original image has no alpha channel then a alpha channel will be added. """, body="""\ wxCHECK_MSG( self->Ok(), NULL, wxT("invalid image") ); wxImage* dest = new wxImage( self->GetWidth(), self->GetHeight(), false ); wxCHECK_MSG( dest && dest->IsOk(), NULL, wxT("unable to create image") ); unsigned rgblen = 3 * self->GetWidth() * self->GetHeight(); unsigned alphalen = self->GetWidth() * self->GetHeight(); byte* src_data = self->GetData(); byte* src_alpha = self->GetAlpha(); byte* dst_data = dest->GetData(); byte* dst_alpha = NULL; // adjust rgb if ( factor_red == 1.0 && factor_green == 1.0 && factor_blue == 1.0) { // nothing to do for RGB memcpy(dst_data, src_data, rgblen); } else { // rgb pixel for pixel for ( unsigned i = 0; i < rgblen; i= i + 3 ) { dst_data[i] = (byte) wxMin( 255, (int) (factor_red * src_data[i]) ); dst_data[i + 1] = (byte) wxMin( 255, (int) (factor_green * src_data[i + 1]) ); dst_data[i + 2] = (byte) wxMin( 255, (int) (factor_blue * src_data[i + 2]) ); } } // adjust the mask colour if ( self->HasMask() ) { dest->SetMaskColour((byte) wxMin( 255, (int) (factor_red * self->GetMaskRed() ) ), (byte) wxMin( 255, (int) (factor_green * self->GetMaskGreen() ) ), (byte) wxMin( 255, (int) (factor_blue * self->GetMaskBlue() ) ) ); } // adjust the alpha channel if ( src_alpha ) { // source image already has alpha information dest->SetAlpha(); // create an empty alpha channel (not initialized) dst_alpha = dest->GetAlpha(); wxCHECK_MSG( dst_alpha, NULL, wxT("unable to create alpha data") ); if ( factor_alpha == 1.0) { // no need to adjust memcpy(dst_alpha, src_alpha, alphalen); } else { // alpha value for alpha value for ( unsigned i = 0; i < alphalen; ++i ) { dst_alpha[i] = (byte) wxMin( 255, (int) (factor_alpha * src_alpha[i]) ); } } } else if ( factor_alpha != 1.0 ) { // no alpha yet but we want to adjust -> create dest->SetAlpha(); // create an empty alpha channel (not initialized) dst_alpha = dest->GetAlpha(); wxCHECK_MSG( dst_alpha, NULL, wxT("unable to create alpha data") ); for ( unsigned i = 0; i < alphalen; ++i ) { dst_alpha[i] = (byte) wxMin( 255, (int) (factor_alpha * 255) ); } } // do we have an alpha channel and a mask in the new image? if ( dst_alpha && dest->HasMask() ) { // make the mask transparent honoring the alpha channel const byte mr = dest->GetMaskRed(); const byte mg = dest->GetMaskGreen(); const byte mb = dest->GetMaskBlue(); for ( unsigned i = 0; i < alphalen; ++i ) { int n = i * 3; dst_alpha[i] = ( dst_data[n] == mr && dst_data[n + 1] == mg && dst_data[n + 2] == mb ) ? wxIMAGE_ALPHA_TRANSPARENT : dst_alpha[i]; } // remove the mask now dest->SetMask(false); } return dest;""", factory=True) c.addProperty('Width GetWidth') c.addProperty('Height GetHeight') c.addProperty('MaskBlue GetMaskBlue') c.addProperty('MaskGreen GetMaskGreen') c.addProperty('MaskRed GetMaskRed') c.addProperty('Type GetType SetType') # For compatibility: module.addPyFunction('EmptyImage', '(width=0, height=0, clear=True)', deprecated="Use :class:`Image` instead.", doc='A compatibility wrapper for the wx.Image(width, height) constructor', body='return Image(width, height, clear)') module.addPyFunction('ImageFromBitmap', '(bitmap)', deprecated="Use bitmap.ConvertToImage instead.", doc='Create a :class:`Image` from a :class:`wx.Bitmap`', body='return bitmap.ConvertToImage()') module.addPyFunction('ImageFromStream', '(stream, type=BITMAP_TYPE_ANY, index=-1)', deprecated="Use :class:`Image` instead.", doc='Load an image from a stream (file-like object)', body='return wx.Image(stream, type, index)') module.addPyFunction('ImageFromData', '(width, height, data)', deprecated="Use :class:`Image` instead.", doc='Compatibility wrapper for creating an image from RGB data', body='return Image(width, height, data)') module.addPyFunction('ImageFromDataWithAlpha', '(width, height, data, alpha)', deprecated="Use :class:`Image` instead.", doc='Compatibility wrapper for creating an image from RGB and Alpha data', body='return Image(width, height, data, alpha)') module.addPyFunction('ImageFromBuffer', '(width, height, dataBuffer, alphaBuffer=None)', doc="""\ Creates a :class:`Image` from the data in `dataBuffer`. The `dataBuffer` parameter must be a Python object that implements the buffer interface, such as a string, array, etc. The `dataBuffer` object is expected to contain a series of RGB bytes and be width*height*3 bytes long. A buffer object can optionally be supplied for the image's alpha channel data, and it is expected to be width*height bytes long. The :class:`Image` will be created with its data and alpha pointers initialized to the memory address pointed to by the buffer objects, thus saving the time needed to copy the image data from the buffer object to the :class:`Image`. While this has advantages, it also has the shoot-yourself-in-the-foot risks associated with sharing a C pointer between two objects. To help alleviate the risk a reference to the data and alpha buffer objects are kept with the :class:`Image`, so that they won't get deleted until after the wx.Image is deleted. However please be aware that it is not guaranteed that an object won't move its memory buffer to a new location when it needs to resize its contents. If that happens then the :class:`Image` will end up referring to an invalid memory location and could cause the application to crash. Therefore care should be taken to not manipulate the objects used for the data and alpha buffers in a way that would cause them to change size. """, body="""\ img = Image(width, height) img.SetDataBuffer(dataBuffer) if alphaBuffer: img.SetAlphaBuffer(alphaBuffer) img._buffer = dataBuffer img._alpha = alphaBuffer return img """) #------------------------------------------------------- c = module.find('wxImageHistogram') c.bases = ['wxObject'] setParamsPyInt('MakeKey') c.find('FindFirstUnusedColour').type = 'void' c.find('FindFirstUnusedColour.r').pyInt = True c.find('FindFirstUnusedColour.g').pyInt = True c.find('FindFirstUnusedColour.b').pyInt = True c.find('FindFirstUnusedColour.startR').pyInt = True c.find('FindFirstUnusedColour.startG').pyInt = True c.find('FindFirstUnusedColour.startB').pyInt = True c.find('FindFirstUnusedColour.r').out = True c.find('FindFirstUnusedColour.g').out = True c.find('FindFirstUnusedColour.b').out = True #------------------------------------------------------- c = module.find('wxImageHandler') c.abstract = True c.addPrivateCopyCtor() c.find('GetLibraryVersionInfo').ignore() c.find('DoGetImageCount').ignore(False) c.find('DoCanRead').ignore(False) #------------------------------------------------------- module.find('wxIMAGE_ALPHA_TRANSPARENT').pyInt = True module.find('wxIMAGE_ALPHA_OPAQUE').pyInt = True module.find('wxIMAGE_ALPHA_THRESHOLD').pyInt = True # These are defines for string objects, not integers, so we can't # generate code for them the same way as integer values. Since they are # #defines we can't just tell SIP that they are global wxString objects # because it will then end up taking the address of temporary values when # it makes the getters for them. So instead we'll just make some python # code to insert into the .py module and hope that the interface file # always has the correct values of these options. pycode = "" for item in module: if 'IMAGE_OPTION' in item.name and isinstance(item, etgtools.DefineDef): item.ignore() name = tools.removeWxPrefix(item.name) value = item.value for txt in ['wxString(', 'wxT(', ')']: value = value.replace(txt, '') pycode += '%s = %s\n' % (name, value) module.addPyCode(pycode) #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module)