
NewClass - adding a new class to wxPerl

see "CONSTANTS" and "EVENTS".
see "CHOOSING A TYPEMAP".
see "OVERLOADING".
see "VIRTUAL METHODS".

Add a new file XS/NewClass.xsp and update the MANIFEST. Choose a relevant .xs file in the top level directory (eg. Controls.xs) and add this line:
INCLUDE_COMMAND: $^X -MExtUtils::XSpp::Cmd -e xspp -- -t typemap.xsp XS/NewClass.xsp
A skeleton for NewClass.xsp:
%module{Wx};
#include <wx/newclass.h> // use the relevant wxWidgets header(s)
%name{Wx::NewClass} class wxNewClass : public wxSomeBaseClass
{
# constructors see the CONSTRUCTORS section
wxNewClass( wxWindow* some_window, const wxString& str );
# destructors
~wxNewClass();
# methods
wxString GetString() const;
void SetString( const wxString& str );
};
Add the typemap definition to typemap.tmpl. See "CHOOSING A TYPEMAP".
If adding a class related to one of the wxPerl submodules (Wx::RichText, Wx::Html, ...) add the .xsp file to the relevant subdirectory and modify the .xs and typemap files in that subdirectory.

There are five typemaps that should work for most wxWidgets objects:
O_NON_WXOBJECT
for all classes that do not derive from wxObject AND do not need to be garbage collected.
O_NON_WXOBJECT_THR
for all classes that do not derive from wxObject AND need to be garbage collected (see "DESTRUCTORS AND THREADS").
O_WXOBJECT
for all classes that derive from wxObject AND do not need to be garbage collected.
O_WXOBJECT_THR
for all classes derived from wxObject AND need to be garbage collected (see "DESTRUCTORS AND THREADS").
O_WXEVTHANDLER
for all classes that derive from wxEvtHandler. See also "CONSTRUCTORS".

For O_WXEVTHANDLER typemaps, there is some additional code that needs to be added to the constructor:
wxNewClass( wxWindow* some_window, const wxString& str )
%code{% RETVAL = new wxNewClass( some_window, str );
wxPli_create_evthandler( aTHX_ RETVAL, CLASS );
%};

For many classes not derived from wxEvtHandler you need to add a destructor to free the C++ object when the Perl object is garbage collected. At the XS++ level this means adding
~wxNewClass();
to the class definition, but there is a catch: the Perl threading model.
Without going into details, this is needed for Perl threads compatibility:
choose either O_NON_WXOBJECT_THR or O_WXOBJECT_THR.
CLONE method
add this code inside the class declaration:
%{
static void
wxNewClass::CLONE()
CODE:
wxPli_thread_sv_clone( aTHX_ CLASS, (wxPliCloneSV)wxPli_detach_object );
%}
modify the destructor like this:
~wxNewClass()
%code%{ wxPli_thread_sv_unregister( aTHX_ "Wx::NewClass", THIS, ST(0) );
delete THIS;
%};

The wrapping of virtual functions whose arguments are simple C++ types (integrals, bool, floating point) and common wxWidgets types (wxString) should be automatic: at the top of the file, load the plugin that handles virtual methods
%loadplugin{build::Wx::XSP::Virtual};
and decorate virtual/pure virtual methods using the %Virtual directive
// pure virtual
virtual wxString GetTitle() const = 0 %Virtual{pure};
// virtual, not pure
virtual int GetBestFittingWidth(unsigned int idx) const %Virtual;
If the class contains pure virtual methods, it will be marked as abstract, and it will have no constructors.
For abstract classes, XS++ will create an additional Perl-level class, called Wx::Pl<classname>; in order to override the virtual methods, you must derive from this class, and not from Wx::<classname>.
TODO allow changing the default behaviour for abstract/concrete classes
TODO allow overriding the class name
TODO allow specifying custom code
TODO handle multiple return values
TODO customized type mapping