From 0363ff23f183ab847bc5b518a64ada652b83b575 Mon Sep 17 00:00:00 2001
From: qu1ck <anlutsenko@gmail.com>
Date: Wed, 15 Aug 2018 02:26:32 -0700
Subject: [PATCH] Add toolbar buttons for action plugins

---
 pcbnew/action_plugin.cpp              | 25 +++++++++++++++++++++++
 pcbnew/action_plugin.h                | 36 +++++++++++++++++++++++++++++++++-
 pcbnew/pcb_edit_frame.cpp             |  2 ++
 pcbnew/pcb_edit_frame.h               |  6 ++++++
 pcbnew/swig/pcbnew_action_plugins.cpp | 37 +++++++++++++++++++++++++++++++++++
 pcbnew/swig/pcbnew_action_plugins.h   |  1 +
 pcbnew/tool_pcb_editor.cpp            |  2 ++
 scripting/kicadplugins.i              |  4 ++++
 8 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/pcbnew/action_plugin.cpp b/pcbnew/action_plugin.cpp
index c10d0fa..e1f0f67 100644
--- a/pcbnew/action_plugin.cpp
+++ b/pcbnew/action_plugin.cpp
@@ -78,6 +78,31 @@ int ACTION_PLUGINS::GetActionMenu( int aIndex )
     return m_actionsList[aIndex]->m_actionMenuId;
 }
 
+ACTION_PLUGIN* ACTION_PLUGINS::GetActionByButton( int aButton )
+{
+    int max = GetActionsCount();
+
+    for( int i = 0; i < max; i++ )
+    {
+        if( m_actionsList[i]->m_actionButtonId == aButton )
+            return m_actionsList[i];
+    }
+
+    return NULL;
+}
+
+
+void ACTION_PLUGINS::SetActionButton( int aIndex, int idButton )
+{
+    m_actionsList[aIndex]->m_actionButtonId = idButton;
+}
+
+
+int ACTION_PLUGINS::GetActionButton( int aIndex )
+{
+    return m_actionsList[aIndex]->m_actionButtonId;
+}
+
 
 ACTION_PLUGIN* ACTION_PLUGINS::GetAction( const wxString& aName )
 {
diff --git a/pcbnew/action_plugin.h b/pcbnew/action_plugin.h
index ff3ed14..17ff2bb 100644
--- a/pcbnew/action_plugin.h
+++ b/pcbnew/action_plugin.h
@@ -44,9 +44,11 @@ public:
     // m_actionMenuId set to 0 means the corresponding menuitem to call this
     // action is not yet created
     int m_actionMenuId;
+    // Same for button id
+    int m_actionButtonId;
 
 public:
-    ACTION_PLUGIN() : m_actionMenuId( 0 ) {}
+    ACTION_PLUGIN() : m_actionMenuId( 0 ), m_actionButtonId( 0 ) {}
     virtual ~ACTION_PLUGIN();
 
     /**
@@ -69,6 +71,12 @@ public:
     virtual wxString GetDescription() = 0;
 
     /**
+     * Function GetIconFileName
+     * @return a path to icon for the action plugin button
+     */
+    virtual wxString GetIconFileName() = 0;
+
+    /**
      * Function GetObject
      * This method gets the pointer to the object from where this action constructs
      * @return  it's a void pointer, as it could be a PyObject or any other
@@ -155,6 +163,32 @@ public:
      */
     static ACTION_PLUGIN* GetActionByMenu( int aMenu );
 
+    /**
+     * Function SetActionButton
+     * Associate a button id to an action plugin
+     * @param aIndex is the action index
+     * @param idButton is the associated menuitem id
+     */
+    static void SetActionButton( int aIndex, int idButton );
+
+
+    /**
+     * Function GetActionButton
+     * Provide button id for a plugin index
+     * @param aIndex is the action index
+     * @return associated menuitem id
+     */
+    static int GetActionButton( int aIndex );
+
+
+    /**
+     * Function GetActionByButton
+     * find action plugin associated to a button id
+     * @param aMenu is the button id (defined with SetActionButton)
+     * @return the associated ACTION_PLUGIN (or null if not found)
+     */
+    static ACTION_PLUGIN* GetActionByButton( int aButton );
+
 
     /**
      * Function GetAction
diff --git a/pcbnew/pcb_edit_frame.cpp b/pcbnew/pcb_edit_frame.cpp
index fef6f8d..1360d1a 100644
--- a/pcbnew/pcb_edit_frame.cpp
+++ b/pcbnew/pcb_edit_frame.cpp
@@ -1249,6 +1249,8 @@ void PCB_EDIT_FRAME::PythonPluginsReload()
         // Action plugins can be modified, therefore the plugins menu
         // must be updated:
         RebuildActionPluginMenus();
+        // Recreate top toolbar to add action plugin buttons
+        ReCreateHToolbar();
     #endif
 #endif
 }
diff --git a/pcbnew/pcb_edit_frame.h b/pcbnew/pcb_edit_frame.h
index 4179353..041e620 100644
--- a/pcbnew/pcb_edit_frame.h
+++ b/pcbnew/pcb_edit_frame.h
@@ -122,6 +122,12 @@ protected:
     void RebuildActionPluginMenus();
 
     /**
+     * Function AddActionPluginTools
+     * Append action plugin buttons to main toolbar
+     */
+    void AddActionPluginTools();
+
+    /**
      * Function OnActionPlugin
      * Launched by the menu when an action is called
      * @param aEvent sent by wx
diff --git a/pcbnew/swig/pcbnew_action_plugins.cpp b/pcbnew/swig/pcbnew_action_plugins.cpp
index 4fb232e..c0b320f 100644
--- a/pcbnew/swig/pcbnew_action_plugins.cpp
+++ b/pcbnew/swig/pcbnew_action_plugins.cpp
@@ -140,6 +140,14 @@ wxString PYTHON_ACTION_PLUGIN::GetDescription()
 }
 
 
+wxString PYTHON_ACTION_PLUGIN::GetIconFileName()
+{
+    PyLOCK lock;
+
+    return CallRetStrMethod( "GetIconFileName" );
+}
+
+
 void PYTHON_ACTION_PLUGIN::Run()
 {
     PyLOCK lock;
@@ -176,6 +184,10 @@ void PCB_EDIT_FRAME::OnActionPlugin( wxCommandEvent& aEvent )
     int id = aEvent.GetId();
 
     ACTION_PLUGIN* actionPlugin = ACTION_PLUGINS::GetActionByMenu( id );
+    if ( !actionPlugin ) {
+      // Try looking by button
+      actionPlugin = ACTION_PLUGINS::GetActionByButton( id );
+    }
 
     if( actionPlugin )
     {
@@ -439,5 +451,30 @@ void PCB_EDIT_FRAME::RebuildActionPluginMenus()
     }
 }
 
+void PCB_EDIT_FRAME::AddActionPluginTools()
+{
+    bool need_separator = true;
+    for( int ii = 0; ii < ACTION_PLUGINS::GetActionsCount(); ii++ )
+    {
+        if( !ACTION_PLUGINS::GetAction( ii )->GetIconFileName().IsEmpty() )
+        {
+            ACTION_PLUGIN* ap = ACTION_PLUGINS::GetAction( ii );
+            if ( need_separator )
+            {
+                KiScaledSeparator( m_mainToolBar, this );
+                need_separator = false;
+            }
+            // Add button
+            // This should check if file exists
+            const wxBitmap icon = wxBitmap( ap->GetIconFileName() , wxBITMAP_TYPE_PNG );
+            wxAuiToolBarItem* button = m_mainToolBar->AddTool( wxID_ANY, wxEmptyString, icon, ap->GetName() );
+            Connect( button->GetId(), wxEVT_COMMAND_MENU_SELECTED,
+                    (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &
+                    PCB_EDIT_FRAME::OnActionPlugin );
+            // Link action plugin to button
+            ACTION_PLUGINS::SetActionButton( ii, button->GetId() );
+        }
+    }
+}
 
 #endif
diff --git a/pcbnew/swig/pcbnew_action_plugins.h b/pcbnew/swig/pcbnew_action_plugins.h
index 08dfa14..2d9c512 100644
--- a/pcbnew/swig/pcbnew_action_plugins.h
+++ b/pcbnew/swig/pcbnew_action_plugins.h
@@ -47,6 +47,7 @@ public:
     wxString    GetCategoryName() override;
     wxString    GetName() override;
     wxString    GetDescription() override;
+    wxString    GetIconFileName() override;
     void        Run() override;
     void*       GetObject() override;
 };
diff --git a/pcbnew/tool_pcb_editor.cpp b/pcbnew/tool_pcb_editor.cpp
index 66b6223..18926b8 100644
--- a/pcbnew/tool_pcb_editor.cpp
+++ b/pcbnew/tool_pcb_editor.cpp
@@ -321,6 +321,8 @@ void PCB_EDIT_FRAME::ReCreateHToolbar()
         m_mainToolBar->AddTool( ID_TOOLBARH_PCB_SCRIPTING_CONSOLE, wxEmptyString,
                                 KiScaledBitmap( py_script_xpm, this ),
                                 _( "Show/Hide the Python Scripting console" ), wxITEM_CHECK );
+
+        AddActionPluginTools();
     }
 #endif
 
diff --git a/scripting/kicadplugins.i b/scripting/kicadplugins.i
index 8c1781d..966f4b8 100644
--- a/scripting/kicadplugins.i
+++ b/scripting/kicadplugins.i
@@ -639,6 +639,7 @@ class ActionPlugin(KiCadPlugin, object):
         self.name = "Undefined Action plugin"
         self.category = "Undefined"
         self.description = ""
+        self.icon_file_name = None
 
     def GetName( self ):
         return self.name
@@ -649,6 +650,9 @@ class ActionPlugin(KiCadPlugin, object):
     def GetDescription( self ):
         return self.description
 
+    def GetIconFileName( self ):
+        return self.icon_file_name
+
     def Run(self):
         return
 
-- 
2.7.4

