Difference between revisions of "Python3 SWIG interface"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
(initial version)
 
m (add category)
 
Line 76: Line 76:
 
MyPyAPI.getRootWindow().addChild(mywin)
 
MyPyAPI.getRootWindow().addChild(mywin)
 
</source>
 
</source>
 +
 +
[[Category:HowTo]]

Latest revision as of 22:22, 30 August 2019

Written for CEGUI 1.0


Works with versions 1.0.x (unstable)

Default branch of CEGUI provide Python3 binding with SWIG. Currently SWIG interface covers a large part of libCEGUIBase, but don't cover any renderer module.

About SWIG

SWIG is wrappers generators, it can generate Python and other APIs without the need writing a lot of wrapper code.

How it works

SWIG parse .i file and generate C++ file, that (in Python case) directly uses libpython (so no depends on boost, pybind or similar). C++ file is build into Python .so lib. SWIG generate also small .py file to support import this lib. Cmake run SWIG on .i and $CXX on generated wrapper code (in Ogre case is very big file, so $CXX need some time to build it).

SWIG automatically generate wrapper from .i file(s) and %include C++ .h files. SWIG .i file is set of % directive, such as:

  • %include "file.h" – add interface from file.h to generated API
  • %{ ... %} to add some C++ stuff (e.g. #include directive with header needed to build whole generated .cpp file)
  • %extend, %proxycode, %ignore to adjust generated API

.h files for classes that should be exposed in generated API must be directly %include in <code>.i file (SWIG do not use #include in %include files as %include). Order of %include is important – first %include base classes, otherwise SWIG generate warning about missing base class and in generated API is missing info about class hierarchy (can't put derived class object to function that get base class object, can't call base class method on derived class object).

Build CEGUI Python3 binding

To build CEGUI Python SWIG interface you should enable CEGUI_BUILD_PYTHON_MODULES_SWIG cmake option:

mkdir build; cd build; cmake .. -D CEGUI_BUILD_PYTHON_MODULES_SWIG=ON && make

This require libpython3 and swig.

Usage CEGUI Python3 binding

Primary intention of this binding is allow use (and create) CEGUI object from Python scripts system in game engines.

Using with boost::python

SWIG generated API can be used with code that use boost::python to expose own interface. For example, if some project use CEGUI and have python API created with boost, it can return some CEGUI object via boost and this object can be used in python with CEGUI SWIG interface (this need only small piece of code to “cast” object between boost and SWIG):

#include "swig2BoostPython.inl"
 
#include <CEGUI/Window.h>
 
PREPARE_EXPOSE_PTR_VIA_SWIG(CEGUI::Window, "CEGUI::Window *");
 
CEGUI::Window * getRootWindow();
 
BOOST_PYTHON_MODULE(MyPyAPI) {
	EXPOSE_PTR_VIA_SWIG(CEGUI::Window);
	boost::python::def(
		"getRootWindow",   &getRootWindow,
		boost::python::return_value_policy<reference_existing_object_via_SWIG>()
	);
}

swig2BoostPython.inl is small, header only, MIT license lib for connect boost and swig interfaces available on bitbucket git repo.

Down-cast CEGUI::Window and subscribeEvent()

SWIG Python interface provide down-casting function for CEGUI::Window class. For example to get CEGUI::FrameWindow form CEGUI::Window you should use CEGUI.toFrameWindow(win).

In SWIG Python interface to subscribeEvent() function should be pass objects of python class with realize event action. This class must have run method witch get event argument and return bool value.This object can't be delete before run events.

example of creating window from python (with close button event)

import CEGUI
import MyPyAPI
 
mywin = CEGUI.WindowManager.getSingleton().loadLayoutFromFile("Info.layout")
class Callback(CEGUI.PySubscriber):
    def run(self, n):
        mywin.hide()
        return True; # must return bool
handleHideInfoWin = Callback() # can't be temporary object !!!
CEGUI.toFrameWindow(mywin).getCloseButton().subscribeEvent( CEGUI.PushButton.EventClicked.c_str(), handleHideInfoWin )
 
MyPyAPI.getRootWindow().addChild(mywin)