← Back to team overview

kicad-developers team mailing list archive

[patch 1/1] kicad-python-event-binding.patch

 

5th python patch: Event Handling

This patch adds the following Python Functions:

common.RegisterCallback ( 'key', func ):

registers func ( def func( param ) ) to be called upon 'key' event 
triggering

common.UnRegisterCallback( 'key', func )

the opposite

Regarding C++ API, it is now possible to declare a new event (DeclareEvent)
and to fire it (TriggerEvent) the following events have been added for test:

kicad::RunScript : fired when a python script is run from the tree 
(param is the script name)
kicad::EditScript : fired when a python script is about to be edited 
(param is the script name)
kicad::TreeContextMenu : fired when a context menu is about to be 
displayed (param is the file name)
kicad::TreeAddFile : fired when a file is about to be added to the 
project tree (param is the file name)


Python support bases are now setup, next patches will only be binding, 
API evolution (and some docs)
---
common/pyhandler.cpp | 82 
++++++++++++++++++++++++++++++++++++++++++++++-----
include/pyhandler.h | 31 +++++++++++++++++++
kicad/treeprj.cpp | 20 +++++++++++-
3 files changed, 124 insertions(+), 9 deletions(-)


 --------------030208030504060401090604 Content-Type: text/x-patch;
name="kicad-python-event-binding.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="kicad-python-event-binding.patch"

5th python patch: Event Handling

This patch adds the following Python Functions:

common.RegisterCallback ( 'key', func ): 

registers func ( def func( param ) ) to be called upon 'key' event triggering

common.UnRegisterCallback( 'key', func )

the opposite


Regarding C++ API, it is now possible to declare a new event (DeclareEvent)
and to fire it (TriggerEvent) the following events have been added for test:

kicad::RunScript : fired when a python script is run from the tree (param is the script name)
kicad::EditScript : fired when a python script is about to be edited (param is the script name)
kicad::TreeContextMenu : fired when a context menu is about to be displayed (param is the file name)
kicad::TreeAddFile : fired when a file is about to be added to the project tree (param is the file name)

---
common/pyhandler.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++-----
include/pyhandler.h | 31 +++++++++++++++++++
kicad/treeprj.cpp | 20 +++++++++++-
3 files changed, 124 insertions(+), 9 deletions(-)


Index: kicad-dev/common/pyhandler.cpp
===================================================================
--- kicad-dev.orig/common/pyhandler.cpp	2007-04-22 22:41:59.000000000 +0200
+++ kicad-dev/common/pyhandler.cpp	2007-04-23 00:19:08.000000000 +0200
@@ -28,11 +28,10 @@

static object ChooseFile( str objTitle, str objMask, object objOpen )
{
- wxString title( extract<const char*>( objTitle ), wxConvLocal );
- wxString mask ( extract<const char*>( objMask ), wxConvLocal );
+ wxString mask = PyHandler::MakeStr( objMask );
int open = extract<int>( objOpen );

- wxString script = EDA_FileSelector( title,
+ wxString script = EDA_FileSelector( PyHandler::MakeStr( objTitle ),
wxEmptyString,	/* Chemin par defaut */
wxEmptyString,	/* nom fichier par defaut */
mask,	/* extension par defaut */
@@ -42,15 +41,23 @@
FALSE
);

- return str( std::string( script.fn_str() ).c_str() );
+ return PyHandler::Convert( script );
}

static void Print( str message ) { std::cout << extract<char *>(message); }

+static void RegisterCb( str objKey, object callback )
+{ PyHandler::GetInstance()->RegisterCallback( PyHandler::MakeStr(objKey), callback ); }
+static void UnRegisterCb( str objKey, object callback )
+{ PyHandler::GetInstance()->UnRegisterCallback( PyHandler::MakeStr(objKey), callback ); }
+
static void init_base_utils(void)
{
- def ( "ChooseFile", &ChooseFile );
- def ( "Print", &Print );
+ def ( "ChooseFile", &ChooseFile );
+ def ( "RegisterCallback", &RegisterCb );
+ def ( "UnRegisterCallback", &UnRegisterCb );
+
+ def ( "Print", &Print );
}

static void InitPyModules() { PyHandler::GetInstance()->InitNextModule(); } // Dummy boost callback
@@ -227,8 +234,67 @@
}
}

-const char * PyHandler::GetVersion()
+const char * PyHandler::GetVersion() { return Py_GetVersion(); }
+
+// Event handling :
+
+void PyHandler::DeclareEvent( const wxString & key ) { m_EventRegistry.push_back( Event( key ) ); }
+
+int PyHandler::GetEventIndex( const wxString & key )
{
-	return Py_GetVersion();
+ for ( unsigned int i = 0; i < m_EventRegistry.size(); i ++ )
+ {
+ if ( m_EventRegistry[i].key == key ) return i;
+ }
+ return -1;
}
+
+void PyHandler::TriggerEvent( const wxString & key ) { TriggerEvent( key, str( "" ) ); }
+void PyHandler::TriggerEvent( const wxString & key, const object & param )
+{
+
+ int i = GetEventIndex( key );
+ if ( -1 == i ) return;
+
+ for ( unsigned int j = 0; j < m_EventRegistry[i].functors.size(); j++ )
+ {
+ try
+ {
+ m_EventRegistry[i].functors[j]( param );
+ }
+ catch (error_already_set)
+ {
+ std::cout << "Error in event " << key.fn_str() << " callback" << std::endl;
+ PyErr_Print();
+ }
+ }
+}
+
+void PyHandler::RegisterCallback( const wxString & key, const object & callback )
+{
+ int i = GetEventIndex( key );
+ if ( -1 == i ) return;
+ m_EventRegistry[i].functors.push_back( callback );
+}
+
+void PyHandler::UnRegisterCallback( const wxString & key, const object & callback )
+{
+ int i = GetEventIndex( key );
+ if ( -1 == i ) return;
+ for ( unsigned int j = 0; j < m_EventRegistry[i].functors.size() ; j++ )
+ {
+ if ( callback == m_EventRegistry[i].functors[j] )
+ {
+ m_EventRegistry[i].functors.erase( m_EventRegistry[i].functors.begin() + j );
+ break;
+ }
+ }
+}
+
+// Object conversion:
+
+wxString PyHandler::MakeStr( const object & objStr ) { return wxString( extract<const char *>( objStr ), wxConvLocal ); }
+
+object PyHandler::Convert( const wxString & wxStr ) { return str( std::string( wxStr.fn_str() ).c_str() ); }
+
// vim: set tabstop=4 :
Index: kicad-dev/include/pyhandler.h
===================================================================
--- kicad-dev.orig/include/pyhandler.h	2007-04-22 22:41:57.000000000 +0200
+++ kicad-dev/include/pyhandler.h	2007-04-23 00:18:25.000000000 +0200
@@ -27,6 +27,8 @@
wxString m_appName;
void RunBaseScripts( const wxString & base );

+
+ // Modules
struct ModuleRecord
{
wxString name;
@@ -37,6 +39,16 @@
std::vector< ModuleRecord > m_ModuleRegistry;
void DoInitModules();

+ // Events
+ struct Event
+ {
+ wxString key;
+ std::vector< boost::python::object > functors;
+
+ Event( const wxString & strKey ) : key( strKey ) {}
+ };
+ std::vector< Event > m_EventRegistry;
+
public:
// Singletton handling:
static PyHandler * GetInstance();
@@ -57,6 +69,25 @@

void InitNextModule();

+ // Event triggering
+
+ // - C++ interface
+ void DeclareEvent( const wxString & key );
+ void TriggerEvent( const wxString & key );
+ void TriggerEvent( const wxString & key, const boost::python::object & param );
+ int GetEventIndex( const wxString & key );
+
+ // - Py Interface
+ void RegisterCallback ( const wxString & key, const boost::python::object & obj );
+ void UnRegisterCallback( const wxString & key, const boost::python::object & obj );
+
+ // Object conversions
+
+ // - Py -> C++
+ static wxString MakeStr( const boost::python::object & objStr );
+
+ // - C++ -> Py
+ static boost::python::object Convert( const wxString & wxStr );
};

// vim: set tabstop=4 :
Index: kicad-dev/kicad/treeprj.cpp
===================================================================
--- kicad-dev.orig/kicad/treeprj.cpp	2007-04-23 00:52:20.000000000 +0200
+++ kicad-dev/kicad/treeprj.cpp	2007-04-23 00:54:53.000000000 +0200
@@ -80,6 +80,11 @@
wxMenuItem *item;

#ifdef KICAD_PYTHON
+ PyHandler::GetInstance()->DeclareEvent( wxT( "kicad::RunScript" ) );
+ PyHandler::GetInstance()->DeclareEvent( wxT( "kicad::EditScript" ) );
+ PyHandler::GetInstance()->DeclareEvent( wxT( "kicad::TreeContextMenu" ) );
+ PyHandler::GetInstance()->DeclareEvent( wxT( "kicad::TreeAddFile" ) );
+
item = new wxMenuItem(&m_PyPopupMenu, ID_PROJECT_RUNPY,
_("&Run"),
_("Run the Python Script") );
@@ -143,6 +148,10 @@
m_TreeProject->SetItemFont(cellule, *g_StdFont);
m_TreeProject->SetItemImage( cellule, type - 1 );
m_TreeProject->SetItemImage( cellule, type - 1, wxTreeItemIcon_Selected );
+
+	#ifdef KICAD_PYTHON
+	PyHandler::GetInstance()->TriggerEvent( wxT("kicad::TreeAddFile"), PyHandler::Convert( name ) );
+	#endif
}

/******************************************/
@@ -207,6 +216,10 @@
tree_id = tree_data->m_Id;
FullFileName = tree_data->m_FileName;

+	#ifdef KICAD_PYTHON
+	PyHandler::GetInstance()->TriggerEvent( wxT("kicad::TreeContextMenu"), PyHandler::Convert( FullFileName ) );
+	#endif
+
switch ( tree_id )
{
case TREE_PY:
@@ -230,7 +243,11 @@
wxString FullFileName = tree_data->m_FileName;
AddDelimiterString( FullFileName );
wxString editorname = GetEditorName();
-	if ( !editorname.IsEmpty() ) ExecuteFile(this, editorname, FullFileName);
+	if ( !editorname.IsEmpty() )
+	{
+	PyHandler::GetInstance()->TriggerEvent( wxT("kicad::EditScript"), PyHandler::Convert( FullFileName ) );
+	ExecuteFile(this, editorname, FullFileName);
+	}
}

#ifdef KICAD_PYTHON
@@ -238,6 +255,7 @@
{
TreePrjItemData * tree_data = (TreePrjItemData*) m_TreeProject->GetItemData(m_TreeProject->GetSelection());
wxString FullFileName = tree_data->m_FileName;
+	PyHandler::GetInstance()->TriggerEvent( wxT("kicad::RunScript"), PyHandler::Convert( FullFileName ) );
PyHandler::GetInstance()->RunScript( FullFileName );
}
#endif
 --------------030208030504060401090604--