
The embedded Python interpreter (used in ExpositionSystemFLTK and ExpositionSystemCocoa) can be used in combination with GUI manifesters to interface with exposed elements. Also, the objects can be built into a Python module, and then used in other Python environments.
Building a Python module out of an exposer is easy. For example, the class Test discussed in the OpenExposition Introduction can become a part of a Python module like this:
#include <expo/ExpositionSystemPython.h> #include "Test.h" using namespace expo; PyMODINIT_FUNC initexpo(void) { ExpositionSystemPython *ES = new ExpositionSystemPython(); ES->AddExposerFactory("Test", new TemplateExposerFactory<TestExposer>()); ES->Run(); }
The main part is specifying the classes to be encapsulated into the MAX external (in this case, TestExposer).
Using a suitable Python script and distutils, the self-contained module can be built. The setup.py script used for the above example looks like this:
from distutils.core import setup, Extension expo = Extension('expo', sources = ['examples/test/TestPython.cpp', \ 'src/ExpositionSystemPython.cpp', 'src/Exposition.cpp', 'src/ExpositionSystem.cpp', \ 'src/PythonExposition.cpp']) setup (name = 'Expo', version = '1.0', description = 'This is an OpenExposition package', ext_modules = [expo])
Executing something like python examples/test/setup.py build build_ext -Iinclude:/usr/local/include from the root OpenExposition folder will build the module and place it in the build/lib* folder. The TestPython example project does this - you can then switch to the build/lib* folder, execute Python, and import the built module (expo).
class TestExposer : public Test, public Exposer { public: // Whenever an Exposer constructor is called, the instance is pushed on a stack // as the current exposer instance. All instantiated expositions are automatically // assigned to the current exposer. TestExposer(string const &name="Test") : Exposer(name) { // this provides access to a method, which we mark as the "final" action of the exposer *new MethodExpo<double,Test>(*this, &Test::sum, "sum") << new Property(Property::final); // this provides direct access to the flag variable *new VariableExpo<bool>(flag, "flag") << new InfluencesProperty(GetExpo("sum")); // this provides direct access to the a variable *new VariableExpo<int>(a, "a") << new InfluencesProperty(GetExpo("sum")); // this provides access to a variable through a set of get/set methods *new PropertyExpo<double, Test>(*this, &Test::GetB, &Test::SetB, "b") << new InfluencesProperty(GetExpo("sum")); // the following call will mark the end of construction for this exposer DoneConstructing(); } }; // end class TestExposer
In self-contained modules, instances of an exposed class have to be instantiated, for example you can do something like x = expo.spawn("Test") and then print x.call("sum"). If you do this in the embedded Python interpreter, it should also bring up the other manifesters (graphical and sound) for the new object.
In the future, the interface should be a lot more "natural" to Python, i.e. allowing statements such as x.sum() and x.a = 2.
Then, in your copy of TestPython.cpp (or whatever you rename it to) target/project, instead of "Test.h" include your own file that defines an OpenExposition interface through a class that is derived from class Exposer, and substitute the name of your class for the one occurence of TestExposer inside TestPython.cpp. Currently, your Exposer class MUST have a default constructor (see the examples above) in order for this to work.