summaryrefslogtreecommitdiff
path: root/pcbnew/scripting
diff options
context:
space:
mode:
Diffstat (limited to 'pcbnew/scripting')
-rw-r--r--pcbnew/scripting/TODO.txt11
-rw-r--r--pcbnew/scripting/board.i117
-rw-r--r--pcbnew/scripting/board_item.i98
-rwxr-xr-xpcbnew/scripting/examples/createFPC40.py60
-rwxr-xr-xpcbnew/scripting/examples/createPcb.py48
-rw-r--r--pcbnew/scripting/examples/hidePcbValuesShowReferences.py14
-rwxr-xr-xpcbnew/scripting/examples/listPcb.py66
-rwxr-xr-xpcbnew/scripting/examples/listPcbLibrary.py12
-rw-r--r--pcbnew/scripting/module.i110
-rw-r--r--pcbnew/scripting/pcbnew.i169
-rw-r--r--pcbnew/scripting/pcbnew_footprint_wizards.cpp361
-rw-r--r--pcbnew/scripting/pcbnew_footprint_wizards.h71
-rw-r--r--pcbnew/scripting/pcbnew_scripting_helpers.cpp109
-rw-r--r--pcbnew/scripting/pcbnew_scripting_helpers.h47
-rw-r--r--pcbnew/scripting/plugins.i35
-rw-r--r--pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py156
-rw-r--r--pcbnew/scripting/plugins/FootprintWizardDrawingAids.py523
-rw-r--r--pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py330
-rw-r--r--pcbnew/scripting/plugins/PadArray.py275
-rw-r--r--pcbnew/scripting/plugins/__init__.py1
-rw-r--r--pcbnew/scripting/plugins/bga_wizard.py98
-rw-r--r--pcbnew/scripting/plugins/circular_pad_array_wizard.py83
-rw-r--r--pcbnew/scripting/plugins/qfp_wizard.py125
-rw-r--r--pcbnew/scripting/plugins/sdip_wizard.py237
-rw-r--r--pcbnew/scripting/plugins/touch_slider_wizard.py205
-rw-r--r--pcbnew/scripting/plugins/uss39_barcode.py149
-rw-r--r--pcbnew/scripting/plugins/zip_wizard.py201
-rw-r--r--pcbnew/scripting/python_console_frame.h105
-rw-r--r--pcbnew/scripting/tests/test1.py11
-rw-r--r--pcbnew/scripting/tests/test2.py8
-rw-r--r--pcbnew/scripting/units.i78
31 files changed, 3913 insertions, 0 deletions
diff --git a/pcbnew/scripting/TODO.txt b/pcbnew/scripting/TODO.txt
new file mode 100644
index 0000000..c0f3160
--- /dev/null
+++ b/pcbnew/scripting/TODO.txt
@@ -0,0 +1,11 @@
+
+* think about documentation, how to do it
+* Action plugins:
+ right click hooks,
+ toolbar hooks,
+ menu hooks,
+* IO plugins
+* better footprint wizard (preview in footprint wizard list)
+
+
+
diff --git a/pcbnew/scripting/board.i b/pcbnew/scripting/board.i
new file mode 100644
index 0000000..da0e10a
--- /dev/null
+++ b/pcbnew/scripting/board.i
@@ -0,0 +1,117 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
+ * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file board.i
+ * @brief Specific BOARD extensions and templates
+ */
+
+
+%extend BOARD
+{
+ %pythoncode
+ %{
+ def GetModules(self): return self.m_Modules
+ def GetDrawings(self): return self.m_Drawings
+ def GetTracks(self): return self.m_Track
+ def GetFullRatsnest(self): return self.m_FullRatsnest
+
+ def Save(self,filename):
+ return SaveBoard(filename,self,IO_MGR.KICAD)
+
+ #
+ # add function, clears the thisown to avoid python from deleting
+ # the object in the garbage collector
+ #
+
+ def Add(self,item):
+ item.thisown=0
+ self.AddNative(item)
+ %}
+
+}
+
+// this is to help python with the * accessor of DLIST templates
+
+%rename(Get) operator BOARD_ITEM*;
+%rename(Get) operator TRACK*;
+%rename(Get) operator D_PAD*;
+%rename(Get) operator MODULE*;
+
+
+// we must translate C++ templates to scripting languages
+
+%template(BOARD_ITEM_List) DLIST<BOARD_ITEM>;
+%template(MODULE_List) DLIST<MODULE>;
+%template(TRACK_List) DLIST<TRACK>;
+%template(PAD_List) DLIST<D_PAD>;
+
+// std::vector templates
+
+%template(VIA_DIMENSION_Vector) std::vector<VIA_DIMENSION>;
+%template (RATSNEST_Vector) std::vector<RATSNEST_ITEM>;
+
+%extend BOARD
+{
+ %pythoncode
+ {
+ def GetNetClasses(self):
+ return self.GetDesignSettings().m_NetClasses
+
+ def GetCurrentNetClassName(self):
+ return self.GetDesignSettings().m_CurrentNetClassName
+
+ def GetViasDimensionsList(self):
+ return self.GetDesignSettings().m_ViasDimensionsList
+
+ def GetTrackWidthList(self):
+ return self.GetDesignSettings().m_TrackWidthList
+ }
+}
+
+
+%extend DRAWSEGMENT
+{
+ %pythoncode
+ {
+ def GetShapeStr(self):
+ return self.ShowShape(self.GetShape())
+ }
+}
+
+%extend BOARD_ITEM
+{
+ %pythoncode
+ {
+ def SetPos(self,p):
+ self.SetPosition(p)
+ self.SetPos0(p)
+
+ def SetStartEnd(self,start,end):
+ self.SetStart(start)
+ self.SetStart0(start)
+ self.SetEnd(end)
+ self.SetEnd0(end)
+ }
+}
diff --git a/pcbnew/scripting/board_item.i b/pcbnew/scripting/board_item.i
new file mode 100644
index 0000000..93f3026
--- /dev/null
+++ b/pcbnew/scripting/board_item.i
@@ -0,0 +1,98 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 Miguel Angel Ajo <miguelangel@nbee.es>
+ * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file board_item.i
+ * @brief board_item helpers, mainly for casting down to all child classes
+ */
+
+
+/* Cast downs from EDA_ITEM/BOARD_ITEM to childs */
+
+%inline
+{
+ BOARD_ITEM* Cast_to_BOARD_ITEM(EDA_ITEM* base) { return dynamic_cast<BOARD_ITEM*>(base); }
+}
+
+%extend BOARD_ITEM
+{
+ TEXTE_PCB* Cast_to_TEXTE_PCB() { return dynamic_cast<TEXTE_PCB*>(self); }
+ DIMENSION* Cast_to_DIMENSION() { return dynamic_cast<DIMENSION*>(self); }
+ MODULE* Cast_to_MODULE() { return dynamic_cast<MODULE*>(self); }
+ TEXTE_MODULE* Cast_to_TEXTE_MODULE() { return dynamic_cast<TEXTE_MODULE*>(self); }
+ DRAWSEGMENT* Cast_to_DRAWSEGMENT() { return dynamic_cast<DRAWSEGMENT*>(self); }
+ MARKER_PCB* Cast_to_MARKER_PCB() { return dynamic_cast<MARKER_PCB*>(self); }
+ BOARD* Cast_to_BOARD() { return dynamic_cast<BOARD*>(self); }
+ EDGE_MODULE* Cast_to_EDGE_MODULE() { return dynamic_cast<EDGE_MODULE*>(self); }
+ D_PAD* Cast_to_D_PAD() { return dynamic_cast<D_PAD*>(self); }
+ TRACK* Cast_to_TRACK() { return dynamic_cast<TRACK*>(self); }
+ VIA* Cast_to_VIA() { return dynamic_cast<VIA*>(self); }
+ ZONE_CONTAINER* Cast_to_ZONE_CONTAINER() { return dynamic_cast<ZONE_CONTAINER*>(self);}
+ PCB_TARGET* Cast_to_PCB_TARGET() { return dynamic_cast<PCB_TARGET*>(self); }
+
+
+ %pythoncode
+ {
+ def Cast(self):
+
+ ct = self.GetClass()
+
+ if ct=="PTEXT":
+ return self.Cast_to_TEXTE_PCB()
+ elif ct=="BOARD":
+ return self.Cast_to_BOARD()
+ elif ct=="DIMENSION":
+ return self.Cast_to_DIMENSION()
+ elif ct=="DRAWSEGMENT":
+ return self.Cast_to_DRAWSEGMENT()
+ elif ct=="MGRAPHIC":
+ return self.Cast_to_EDGE_MODULE()
+ elif ct=="MODULE":
+ return self.Cast_to_MODULE()
+ elif ct=="PAD":
+ return self.Cast_to_D_PAD()
+ elif ct=="MTEXT":
+ return self.Cast_to_TEXTE_MODULE()
+ elif ct=="VIA":
+ return self.Cast_to_VIA()
+ elif ct=="TRACK":
+ return self.Cast_to_TRACK()
+ elif ct=="PCB_TARGET":
+ return self.Cast_to_PCB_TARGET()
+ elif ct=="ZONE_CONTAINER":
+ return self.Cast_to_ZONE_CONTAINER()
+ else:
+ return None
+
+
+ def Duplicate(self):
+
+ ct = self.GetClass()
+
+ if ct=="BOARD":
+ return None
+ else:
+ return Cast_to_BOARD_ITEM(self.Clone()).Cast()
+ }
+}
diff --git a/pcbnew/scripting/examples/createFPC40.py b/pcbnew/scripting/examples/createFPC40.py
new file mode 100755
index 0000000..7c6568e
--- /dev/null
+++ b/pcbnew/scripting/examples/createFPC40.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python2.7
+from pcbnew import *
+
+size_025_160mm = wxSizeMM(0.25,1.6)
+size_150_200mm = wxSizeMM(1.50,2.0)
+pads = 40
+
+# create a blank board
+pcb = BOARD()
+
+pcb.m_NetClasses.GetDefault().SetClearance(FromMM(0.1))
+
+# create a new module, it's parent is our previously created pcb
+module = MODULE(pcb)
+module.SetReference("FPC"+str(pads)) # give it a reference name
+module.Reference().SetPos0(wxPointMM(-1,-1))
+pcb.Add(module) # add it to our pcb
+m_pos = wxPointMM(50,50)
+module.SetPosition(m_pos)
+
+# create a pad array and add it to the module
+
+
+def smdRectPad(module,size,pos,name):
+ pad = D_PAD(module)
+ pad.SetSize(size)
+ pad.SetShape(PAD_RECT)
+ pad.SetAttribute(PAD_SMD)
+ pad.SetLayerMask(PAD_SMD_DEFAULT_LAYERS)
+ pad.SetPos0(pos)
+ pad.SetPadName(name)
+ return pad
+
+for n in range (0,pads):
+ pad = smdRectPad(module,size_025_160mm,wxPointMM(0.5*n,0),str(n+1))
+ module.Add(pad)
+
+
+pad_s0 = smdRectPad(module,size_150_200mm,wxPointMM(-1.6,1.3),"0")
+pad_s1 = smdRectPad(module,size_150_200mm,wxPointMM((pads-1)*0.5+1.6,1.3),"0")
+module.Add(pad_s0)
+module.Add(pad_s1)
+
+e = EDGE_MODULE(module)
+e.SetStart0(wxPointMM(-1,0))
+e.SetEnd0(wxPointMM(0,0))
+e.SetWidth(FromMM(0.2))
+e.SetLayer(EDGE_LAYER)
+e.SetShape(S_SEGMENT)
+module.Add(e)
+
+# save the PCB to disk
+fpid = FPID("FPC"+str(pads)) #the name in library
+module.SetFPID( fpid )
+
+try:
+ FootprintLibCreate("fpc40.mod")
+except:
+ pass # we try to create, but may be it exists already
+FootprintSave("fpc40.mod",module)
diff --git a/pcbnew/scripting/examples/createPcb.py b/pcbnew/scripting/examples/createPcb.py
new file mode 100755
index 0000000..21c3803
--- /dev/null
+++ b/pcbnew/scripting/examples/createPcb.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python2.7
+from pcbnew import *
+
+size_0_6mm = wxSizeMM(0.6,0.6)
+size_1_0mm = wxSizeMM(1.0,1.0)
+
+# create a blank board
+pcb = BOARD()
+
+pcb.m_NetClasses.GetDefault().SetClearance(FromMM(0.1))
+
+# create a new module, it's parent is our previously created pcb
+module = MODULE(pcb)
+module.SetReference("M1") # give it a reference name
+module.Reference().SetPos0(wxPointMM(-10,-10))
+pcb.Add(module) # add it to our pcb
+m_pos = wxPointMM(50,50)
+module.SetPosition(m_pos)
+
+# create a pad array and add it to the module
+n = 1
+for y in range (0,10):
+ for x in range (0,10):
+ pad = D_PAD(module)
+ pad.SetDrillSize(size_0_6mm)
+ pad.SetSize(size_1_0mm)
+ pt = wxPointMM(1.27*x,1.27*y)
+ pad.SetPos0(pt);
+ #pad.SetPosition(pt)
+ pad.SetPadName(str(n))
+ module.Add(pad)
+ n+=1
+
+
+# save the PCB to disk
+pcb.Save("my2.kicad_pcb")
+pcb.Save("my2.brd")
+
+pcb = LoadBoard("my2.kicad_pcb")
+
+print map( lambda x: x.GetReference() , list(pcb.GetModules()))
+
+for m in pcb.GetModules():
+ for p in m.Pads():
+ print p.GetPadName(), p.GetPosition(), p.GetOffset()
+
+
+# pcb.GetDesignSettings()
diff --git a/pcbnew/scripting/examples/hidePcbValuesShowReferences.py b/pcbnew/scripting/examples/hidePcbValuesShowReferences.py
new file mode 100644
index 0000000..6b37842
--- /dev/null
+++ b/pcbnew/scripting/examples/hidePcbValuesShowReferences.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+import sys
+from pcbnew import *
+
+filename=sys.argv[1]
+
+pcb = LoadBoard(filename)
+
+for module in pcb.GetModules():
+ print "* Module: %s"%module.GetReference()
+ module.Value().SetVisible(False) # set Value as Hidden
+ module.Reference().SetVisible(True) # set Reference as Visible
+
+pcb.Save("mod_"+filename)
diff --git a/pcbnew/scripting/examples/listPcb.py b/pcbnew/scripting/examples/listPcb.py
new file mode 100755
index 0000000..60ed093
--- /dev/null
+++ b/pcbnew/scripting/examples/listPcb.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+import sys
+from pcbnew import *
+
+filename=sys.argv[1]
+
+pcb = LoadBoard(filename)
+
+ToUnits = ToMM
+FromUnits = FromMM
+#ToUnits=ToMils
+#FromUnits=FromMils
+
+print "LISTING VIAS:"
+
+for item in pcb.GetTracks():
+ if type(item) is VIA:
+
+ pos = item.GetPosition()
+ drill = item.GetDrillValue()
+ width = item.GetWidth()
+ print " * Via: %s - %f/%f "%(ToUnits(pos),ToUnits(drill),ToUnits(width))
+
+ elif type(item) is TRACK:
+
+ start = item.GetStart()
+ end = item.GetEnd()
+ width = item.GetWidth()
+
+ print " * Track: %s to %s, width %f" % (ToUnits(start),ToUnits(end),ToUnits(width))
+
+ else:
+ print "Unknown type %s" % type(item)
+
+print ""
+print "LIST DRAWINGS:"
+
+for item in pcb.GetDrawings():
+ if type(item) is TEXTE_PCB:
+ print "* Text: '%s' at %s"%(item.GetText(), item.GetPosition())
+ elif type(item) is DRAWSEGMENT:
+ print "* Drawing: %s"%item.GetShapeStr() # dir(item)
+ else:
+ print type(item)
+
+print ""
+print "LIST MODULES:"
+
+for module in pcb.GetModules():
+ print "* Module: %s at %s"%(module.GetReference(),ToUnits(module.GetPosition()))
+
+print ""
+print "Ratsnest cnt:",len(pcb.GetFullRatsnest())
+print "track w cnt:",len(pcb.GetTrackWidthList())
+print "via s cnt:",len(pcb.GetViasDimensionsList())
+
+print ""
+print "LIST ZONES:", pcb.GetAreaCount()
+
+for idx in range(0, pcb.GetAreaCount()):
+ zone=pcb.GetArea(idx)
+ print "zone:", idx, "priority:", zone.GetPriority(), "netname", zone.GetNetname()
+
+print ""
+print "NetClasses:", pcb.GetNetClasses().GetCount(),
+
diff --git a/pcbnew/scripting/examples/listPcbLibrary.py b/pcbnew/scripting/examples/listPcbLibrary.py
new file mode 100755
index 0000000..8262c17
--- /dev/null
+++ b/pcbnew/scripting/examples/listPcbLibrary.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+from pcbnew import *
+
+lst = FootprintEnumerate("/usr/share/kicad/modules/sockets.mod")
+
+for name in lst:
+ m = FootprintLoad("/usr/share/kicad/modules/sockets.mod",name)
+ print name,"->",m.GetLibRef(), m.GetReference()
+
+ for p in m.Pads():
+ print "\t",p.GetPadName(),p.GetPosition(),p.GetPos0(), p.GetOffset()
+
diff --git a/pcbnew/scripting/module.i b/pcbnew/scripting/module.i
new file mode 100644
index 0000000..21902bf
--- /dev/null
+++ b/pcbnew/scripting/module.i
@@ -0,0 +1,110 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
+ * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file module.i
+ * @brief Specific BOARD extensions and templates
+ */
+
+
+%extend MODULE
+{
+ %pythoncode
+ %{
+
+ #def SaveToLibrary(self,filename):
+ # return SaveModuleToLibrary(filename,self)
+
+ #
+ # add function, clears the thisown to avoid python from deleting
+ # the object in the garbage collector
+ #
+
+ def Add(self,item):
+
+ itemC = item.Cast()
+
+ if type(itemC) is D_PAD:
+ item.thisown=0
+ self.Pads().PushBack(itemC)
+ elif type(itemC) in [ TEXTE_PCB, DIMENSION, TEXTE_MODULE, DRAWSEGMENT,EDGE_MODULE]:
+ item.thisown = 0
+ self.GraphicalItems().PushBack(item)
+ %}
+
+}
+
+%pythoncode
+{
+
+ def GetPluginForPath(lpath):
+ return IO_MGR.PluginFind(IO_MGR.LEGACY)
+
+ def FootprintEnumerate(lpath):
+ plug = GetPluginForPath(lpath)
+ return plug.FootprintEnumerate(lpath)
+
+ def FootprintLoad(lpath,name):
+ plug = GetPluginForPath(lpath)
+ return plug.FootprintLoad(lpath,name)
+
+ def FootprintSave(lpath,module):
+ plug = GetPluginForPath(lpath)
+ return plug.FootprintSave(lpath,module)
+
+ def FootprintDelete(lpath,name):
+ plug = GetPluginForPath(lpath)
+ plug.FootprintDelete(lpath,name)
+
+ def FootprintLibCreate(lpath):
+ plug = GetPluginForPath(lpath)
+ plug.FootprintLibCreate(lpath)
+
+ def FootprintLibDelete(lpath):
+ plug = GetPluginForPath(lpath)
+ plug.FootprintLibDelete(lpath)
+
+ def FootprintIsWritable(lpath):
+ plug = GetPluginForPath(lpath)
+ plug.FootprintLibIsWritable(lpath)
+}
+
+%{
+ MODULE *PyModule_to_MODULE(PyObject *obj0)
+ {
+ void *argp;
+ int res1 = SWIG_ConvertPtr(obj0, &argp,SWIGTYPE_p_MODULE, 0 | 0 );
+ if (!SWIG_IsOK(res1))
+ {
+ SWIG_exception_fail(SWIG_ArgError(res1), "Converting object to MODULE*");
+ }
+
+ return (MODULE*)argp;
+
+ fail:
+ return NULL;
+
+ }
+
+%}
diff --git a/pcbnew/scripting/pcbnew.i b/pcbnew/scripting/pcbnew.i
new file mode 100644
index 0000000..4e8c7b4
--- /dev/null
+++ b/pcbnew/scripting/pcbnew.i
@@ -0,0 +1,169 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
+ * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file pcbnew.i
+ * @brief Specific pcbnew wrappers
+ */
+
+
+%module pcbnew
+
+%feature("autodoc", "1");
+#ifdef ENABLE_DOCSTRINGS_FROM_DOXYGEN
+%include "docstrings.i"
+#endif
+
+%include "kicad.i"
+
+// ignore a couple of items that generate warnings from swig built code
+
+%ignore BOARD_ITEM::ZeroOffset;
+%ignore D_PAD::m_PadSketchModePenSize;
+
+// rename the Add method of classes to Add native, so we will handle
+// the Add method in python
+
+%rename(AddNative) *::Add;
+
+// fix method names conflicts
+%rename(AddChild) MODULE::Add;
+%rename(RemoveChild) MODULE::Remove;
+%rename(DeleteChild) MODULE::Delete;
+
+%exception {
+ try{
+ $action
+ }
+ catch( IO_ERROR e )
+ {
+ std::string str = TO_UTF8( e.errorText );
+ str += '\n';
+ PyErr_SetString( PyExc_IOError, str.c_str() );
+ return NULL;
+ }
+ catch( std::exception &e )
+ {
+ std::string str = e.what();
+ str += '\n';
+ PyErr_SetString( PyExc_IOError, str.c_str() );
+ return NULL;
+ }
+ catch( ... )
+ {
+ SWIG_fail;
+ }
+}
+%include exception.i
+
+
+// this is what it must be included in the wrapper .cxx code to compile
+
+%{
+ #include <wx_python_helpers.h>
+ #include <class_board_item.h>
+ #include <class_board_connected_item.h>
+ #include <class_board_design_settings.h>
+ #include <class_board.h>
+ #include <class_module.h>
+ #include <class_track.h>
+ #include <class_zone.h>
+ #include <zones.h>
+ #include <layers_id_colors_and_visibility.h>
+ #include <class_pad.h>
+ #include <pad_shapes.h>
+ #include <class_netinfo.h>
+ #include <class_pcb_text.h>
+ #include <class_dimension.h>
+ #include <class_drawsegment.h>
+ #include <class_marker_pcb.h>
+ #include <class_mire.h>
+ #include <class_text_mod.h>
+ #include <class_edge_mod.h>
+ #include <dlist.h>
+ #include <class_zone_settings.h>
+ #include <class_netclass.h>
+ #include <class_netinfo.h>
+ #include <pcbnew_scripting_helpers.h>
+
+ #include <plotcontroller.h>
+ #include <pcb_plot_params.h>
+ #include <exporters/gendrill_Excellon_writer.h>
+ #include <colors.h>
+
+ BOARD *GetBoard(); /* get current editor board */
+%}
+
+
+%{
+ #include <io_mgr.h>
+ #include <kicad_plugin.h>
+%}
+
+%include <class_board_item.h>
+%include <class_board_connected_item.h>
+%include <class_board_design_settings.h>
+%include <class_board.h>
+%include <class_module.h>
+%include <class_track.h>
+%include <class_zone.h>
+%include <zones.h>
+%include <layers_id_colors_and_visibility.h>
+%include <class_pad.h>
+%include <pad_shapes.h>
+%include <class_netinfo.h>
+%include <class_pcb_text.h>
+%include <class_dimension.h>
+%include <class_drawsegment.h>
+%include <class_marker_pcb.h>
+%include <class_mire.h>
+%include <class_text_mod.h>
+%include <class_edge_mod.h>
+%include <dlist.h>
+%include <class_zone_settings.h>
+%include <class_netclass.h>
+%include <class_netinfo.h>
+
+%include <plotcontroller.h>
+%include <pcb_plot_params.h>
+%include <plot_common.h>
+%include <exporters/gendrill_Excellon_writer.h>
+%include <colors.h>
+
+%include "board_item.i"
+
+%include <pcbnew_scripting_helpers.h>
+
+
+// ignore RELEASER as nested classes are still unsupported by swig
+%ignore IO_MGR::RELEASER;
+%include <io_mgr.h>
+%include <kicad_plugin.h>
+
+%include "board.i"
+%include "module.i"
+%include "plugins.i"
+%include "units.i"
+
+
diff --git a/pcbnew/scripting/pcbnew_footprint_wizards.cpp b/pcbnew/scripting/pcbnew_footprint_wizards.cpp
new file mode 100644
index 0000000..e0f3854
--- /dev/null
+++ b/pcbnew/scripting/pcbnew_footprint_wizards.cpp
@@ -0,0 +1,361 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013 NBEE Embedded Systems SL, Miguel Angel Ajo <miguelangel@ajo.es>
+ * Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file pcbnew_footprint_wizards.cpp
+ * @brief Class PCBNEW_PYTHON_FOOTPRINT_WIZARDS
+ */
+
+#include "pcbnew_footprint_wizards.h"
+#include <python_scripting.h>
+#include <stdio.h>
+#include <macros.h>
+
+
+PYTHON_FOOTPRINT_WIZARD::PYTHON_FOOTPRINT_WIZARD( PyObject* aWizard )
+{
+ PyLOCK lock;
+
+ this->m_PyWizard = aWizard;
+ Py_XINCREF( aWizard );
+}
+
+
+PYTHON_FOOTPRINT_WIZARD::~PYTHON_FOOTPRINT_WIZARD()
+{
+ PyLOCK lock;
+
+ Py_XDECREF( this->m_PyWizard );
+}
+
+
+PyObject* PYTHON_FOOTPRINT_WIZARD::CallMethod( const char* aMethod, PyObject* aArglist )
+{
+ PyLOCK lock;
+
+ PyErr_Clear();
+ // pFunc is a new reference to the desired method
+ PyObject* pFunc = PyObject_GetAttrString( this->m_PyWizard, aMethod );
+
+ if( pFunc && PyCallable_Check( pFunc ) )
+ {
+ PyObject* result = PyObject_CallObject( pFunc, aArglist );
+
+ if( PyErr_Occurred() )
+ {
+#if 1 // defined(DEBUG)
+ wxMessageBox( PyErrStringWithTraceback(),
+ wxT( "Exception on python footprint wizard code" ),
+ wxICON_ERROR | wxOK );
+#endif
+ }
+
+ if( result )
+ {
+ Py_XDECREF( pFunc );
+ return result;
+ }
+ }
+ else
+ {
+ printf( "method not found, or not callable: %s\n", aMethod );
+ }
+
+ if( pFunc )
+ {
+ Py_XDECREF( pFunc );
+ }
+
+ return NULL;
+}
+
+
+wxString PYTHON_FOOTPRINT_WIZARD::CallRetStrMethod( const char* aMethod, PyObject* aArglist )
+{
+ wxString ret;
+ PyLOCK lock;
+
+ PyObject* result = CallMethod( aMethod, aArglist );
+
+ if( result )
+ {
+ const char* str_res = PyString_AsString( result );
+ ret = FROM_UTF8( str_res );
+ Py_DECREF( result );
+ }
+
+ return ret;
+}
+
+
+wxArrayString PYTHON_FOOTPRINT_WIZARD::CallRetArrayStrMethod( const char* aMethod,
+ PyObject* aArglist )
+{
+ wxArrayString ret;
+ wxString str_item;
+ PyLOCK lock;
+
+ PyObject* result = CallMethod( aMethod, aArglist );
+
+ if( result )
+ {
+ if( !PyList_Check( result ) )
+ {
+ Py_DECREF( result );
+ ret.Add( wxT(
+ "PYTHON_FOOTPRINT_WIZARD::CallRetArrayStrMethod, result is not a list" ),
+ 1 );
+ return ret;
+ }
+
+ ret = PyArrayStringToWx( result );
+
+ Py_DECREF( result );
+ }
+
+ return ret;
+}
+
+
+wxString PYTHON_FOOTPRINT_WIZARD::GetName()
+{
+ PyLOCK lock;
+
+ return CallRetStrMethod( "GetName" );
+}
+
+
+wxString PYTHON_FOOTPRINT_WIZARD::GetImage()
+{
+ PyLOCK lock;
+
+ return CallRetStrMethod( "GetImage" );
+}
+
+
+wxString PYTHON_FOOTPRINT_WIZARD::GetDescription()
+{
+ PyLOCK lock;
+
+ return CallRetStrMethod( "GetDescription" );
+}
+
+
+int PYTHON_FOOTPRINT_WIZARD::GetNumParameterPages()
+{
+ int ret = 0;
+ PyLOCK lock;
+
+ // Time to call the callback
+ PyObject* result = CallMethod( "GetNumParameterPages", NULL );
+
+ if( result )
+ {
+ if( !PyInt_Check( result ) )
+ return -1;
+
+ ret = PyInt_AsLong( result );
+ Py_DECREF( result );
+ }
+
+ return ret;
+}
+
+
+wxString PYTHON_FOOTPRINT_WIZARD::GetParameterPageName( int aPage )
+{
+ wxString ret;
+ PyLOCK lock;
+
+ // Time to call the callback
+ PyObject* arglist = Py_BuildValue( "(i)", aPage );
+ PyObject* result = CallMethod( "GetParameterPageName", arglist );
+
+ Py_DECREF( arglist );
+
+ if( result )
+ {
+ const char* str_res = PyString_AsString( result );
+ ret = FROM_UTF8( str_res );
+ Py_DECREF( result );
+ }
+
+ return ret;
+}
+
+
+wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterNames( int aPage )
+{
+ wxArrayString ret;
+ PyLOCK lock;
+
+ PyObject* arglist = Py_BuildValue( "(i)", aPage );
+
+ ret = CallRetArrayStrMethod( "GetParameterNames", arglist );
+ Py_DECREF( arglist );
+
+ for( unsigned i = 0; i < ret.GetCount(); i++ )
+ {
+ wxString rest;
+ wxString item = ret[i];
+
+ if( item.StartsWith( wxT( "*" ), &rest ) )
+ {
+ ret[i] = rest;
+ }
+ }
+
+ return ret;
+}
+
+
+wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterTypes( int aPage )
+{
+ wxArrayString ret;
+ PyLOCK lock;
+
+ PyObject* arglist = Py_BuildValue( "(i)", aPage );
+
+ ret = CallRetArrayStrMethod( "GetParameterNames", arglist );
+ Py_DECREF( arglist );
+
+ for( unsigned i = 0; i<ret.GetCount(); i++ )
+ {
+ wxString rest;
+ wxString item = ret[i];
+
+ if( item.StartsWith( wxT( "*" ), &rest ) )
+ {
+ ret[i] = wxT( "UNITS" ); // units
+ }
+ else
+ {
+ ret[i] = wxT( "IU" ); // internal units
+ }
+ }
+
+ return ret;
+}
+
+
+wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterValues( int aPage )
+{
+ PyLOCK lock;
+
+ PyObject* arglist = Py_BuildValue( "(i)", aPage );
+ wxArrayString ret = CallRetArrayStrMethod( "GetParameterValues", arglist );
+
+ Py_DECREF( arglist );
+
+ return ret;
+}
+
+
+wxArrayString PYTHON_FOOTPRINT_WIZARD::GetParameterErrors( int aPage )
+{
+ PyLOCK lock;
+
+ PyObject* arglist = Py_BuildValue( "(i)", aPage );
+ wxArrayString ret = CallRetArrayStrMethod( "GetParameterErrors", arglist );
+
+ Py_DECREF( arglist );
+
+ return ret;
+}
+
+
+wxString PYTHON_FOOTPRINT_WIZARD::SetParameterValues( int aPage, wxArrayString& aValues )
+{
+ int len = aValues.size();
+
+ PyLOCK lock;
+
+ PyObject* py_list = PyList_New( len );
+
+ for( int i = 0; i < len; i++ )
+ {
+ wxString& str = aValues[i];
+ PyObject* py_str = PyString_FromString( (const char*) str.mb_str() );
+ PyList_SetItem( py_list, i, py_str );
+ }
+
+ PyObject* arglist;
+
+ arglist = Py_BuildValue( "(i,O)", aPage, py_list );
+ wxString res = CallRetStrMethod( "SetParameterValues", arglist );
+ Py_DECREF( arglist );
+
+ return res;
+}
+
+
+// this is a SWIG function declaration -from module.i
+MODULE* PyModule_to_MODULE( PyObject* obj0 );
+
+
+MODULE* PYTHON_FOOTPRINT_WIZARD::GetFootprint( wxString * aMessages )
+{
+ PyLOCK lock;
+
+ PyObject* result = CallMethod( "GetFootprint", NULL );
+
+ if( aMessages )
+ *aMessages = CallRetStrMethod( "GetBuildMessages", NULL );
+
+ if( !result )
+ return NULL;
+
+ PyObject* obj = PyObject_GetAttrString( result, "this" );
+
+ if( PyErr_Occurred() )
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ MODULE* mod = PyModule_to_MODULE( obj );
+
+ return mod;
+}
+
+
+void* PYTHON_FOOTPRINT_WIZARD::GetObject()
+{
+ return (void*) m_PyWizard;
+}
+
+
+void PYTHON_FOOTPRINT_WIZARDS::register_wizard( PyObject* aPyWizard )
+{
+ PYTHON_FOOTPRINT_WIZARD* fw = new PYTHON_FOOTPRINT_WIZARD( aPyWizard );
+
+ fw->register_wizard();
+}
+
+
+void PYTHON_FOOTPRINT_WIZARDS::deregister_wizard( PyObject* aPyWizard )
+{
+ // deregister also destroyes the previously created "PYTHON_FOOTPRINT_WIZARD object"
+ FOOTPRINT_WIZARDS::deregister_object( (void*) aPyWizard );
+}
diff --git a/pcbnew/scripting/pcbnew_footprint_wizards.h b/pcbnew/scripting/pcbnew_footprint_wizards.h
new file mode 100644
index 0000000..ada111f
--- /dev/null
+++ b/pcbnew/scripting/pcbnew_footprint_wizards.h
@@ -0,0 +1,71 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013 NBEE Embedded Systems SL, Miguel Angel Ajo <miguelangel@ajo.es>
+ * Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file pcbnew_footprint_wizards.h
+ * @brief Class PCBNEW_FOOTPRINT_WIZARDS
+ */
+
+#ifndef PCBNEW_FOOTPRINT_WIZARDS_H
+#define PCBNEW_FOOTPRINT_WIZARDS_H
+#include <Python.h>
+#include <vector>
+#include <class_footprint_wizard.h>
+
+
+class PYTHON_FOOTPRINT_WIZARD : public FOOTPRINT_WIZARD
+{
+ PyObject* m_PyWizard;
+ PyObject* CallMethod( const char* aMethod, PyObject* aArglist = NULL );
+ wxString CallRetStrMethod( const char* aMethod, PyObject* aArglist = NULL );
+ wxArrayString CallRetArrayStrMethod( const char* aMethod,
+ PyObject* aArglist = NULL );
+
+public:
+ PYTHON_FOOTPRINT_WIZARD( PyObject* wizard );
+ ~PYTHON_FOOTPRINT_WIZARD();
+ wxString GetName();
+ wxString GetImage();
+ wxString GetDescription();
+ int GetNumParameterPages();
+ wxString GetParameterPageName( int aPage );
+ wxArrayString GetParameterNames( int aPage );
+ wxArrayString GetParameterTypes( int aPage );
+ wxArrayString GetParameterValues( int aPage );
+ wxArrayString GetParameterErrors( int aPage );
+ // must return an empty string or an error description
+ wxString SetParameterValues( int aPage, wxArrayString& aValues );
+ MODULE* GetFootprint( wxString * aMessages );
+ void* GetObject();
+};
+
+
+class PYTHON_FOOTPRINT_WIZARDS
+{
+public:
+ static void register_wizard( PyObject* aPyWizard );
+ static void deregister_wizard( PyObject* aPyWizard );
+};
+
+#endif /* PCBNEW_FOOTPRINT_WIZARDS_H */
diff --git a/pcbnew/scripting/pcbnew_scripting_helpers.cpp b/pcbnew/scripting/pcbnew_scripting_helpers.cpp
new file mode 100644
index 0000000..62b21b3
--- /dev/null
+++ b/pcbnew/scripting/pcbnew_scripting_helpers.cpp
@@ -0,0 +1,109 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
+ * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file pcbnew_scripting_helpers.cpp
+ * @brief Scripting helper functions for pcbnew functionality
+ */
+
+#include <Python.h>
+
+#include <pcbnew_scripting_helpers.h>
+#include <pcbnew.h>
+#include <pcbnew_id.h>
+#include <build_version.h>
+#include <class_board.h>
+#include <kicad_string.h>
+#include <io_mgr.h>
+#include <macros.h>
+#include <stdlib.h>
+
+static PCB_EDIT_FRAME* PcbEditFrame = NULL;
+
+BOARD* GetBoard()
+{
+ if( PcbEditFrame )
+ return PcbEditFrame->GetBoard();
+ else
+ return NULL;
+}
+
+
+void ScriptingSetPcbEditFrame( PCB_EDIT_FRAME* aPCBEdaFrame )
+{
+ PcbEditFrame = aPCBEdaFrame;
+}
+
+
+BOARD* LoadBoard( wxString& aFileName )
+{
+ if( aFileName.EndsWith( wxT( ".kicad_pcb" ) ) )
+ return LoadBoard( aFileName, IO_MGR::KICAD );
+
+ else if( aFileName.EndsWith( wxT( ".brd" ) ) )
+ return LoadBoard( aFileName, IO_MGR::LEGACY );
+
+ // as fall back for any other kind use the legacy format
+ return LoadBoard( aFileName, IO_MGR::LEGACY );
+}
+
+
+BOARD* LoadBoard( wxString& aFileName, IO_MGR::PCB_FILE_T aFormat )
+{
+ return IO_MGR::Load( aFormat, aFileName );
+}
+
+
+bool SaveBoard( wxString& aFilename, BOARD* aBoard )
+{
+ return SaveBoard( aFilename, aBoard, IO_MGR::KICAD );
+}
+
+
+bool SaveBoard( wxString& aFileName, BOARD* aBoard,
+ IO_MGR::PCB_FILE_T aFormat )
+{
+ aBoard->m_Status_Pcb &= ~CONNEXION_OK;
+ aBoard->SynchronizeNetsAndNetClasses();
+ aBoard->GetDesignSettings().SetCurrentNetClass( NETCLASS::Default );
+
+#if 0
+ wxString header;
+ PROPERTIES props;
+
+ if( aFormat==IO_MGR::LEGACY )
+ {
+ header = wxString::Format(
+ wxT( "PCBNEW-BOARD Version %d date %s\n\n# Created by Pcbnew%s scripting\n\n" ),
+ LEGACY_BOARD_FILE_VERSION, DateAndTime().GetData(),
+ GetBuildVersion().GetData() );
+ props["header"] = header;
+ }
+
+ IO_MGR::Save( aFormat, aFileName, aBoard, &props );
+#else
+ IO_MGR::Save( aFormat, aFileName, aBoard, NULL );
+#endif
+ return true;
+}
diff --git a/pcbnew/scripting/pcbnew_scripting_helpers.h b/pcbnew/scripting/pcbnew_scripting_helpers.h
new file mode 100644
index 0000000..bff3d0e
--- /dev/null
+++ b/pcbnew/scripting/pcbnew_scripting_helpers.h
@@ -0,0 +1,47 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013 NBEE Embedded Systems SL, Miguel Angel Ajo <miguelangel@ajo.es>
+ * Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __PCBNEW_SCRIPTING_HELPERS_H
+#define __PCBNEW_SCRIPTING_HELPERS_H
+
+#include <wxPcbStruct.h>
+#include <io_mgr.h>
+/* we could be including all these methods as static in a class, but
+ * we want plain pcbnew.<method_name> access from python */
+
+#ifndef SWIG
+void ScriptingSetPcbEditFrame( PCB_EDIT_FRAME* aPCBEdaFrame );
+
+#endif
+
+BOARD* GetBoard();
+
+BOARD* LoadBoard( wxString& aFileName, IO_MGR::PCB_FILE_T aFormat );
+BOARD* LoadBoard( wxString& aFileName );
+
+bool SaveBoard( wxString& aFileName, BOARD* aBoard, IO_MGR::PCB_FILE_T aFormat );
+bool SaveBoard( wxString& aFileName, BOARD* aBoard );
+
+
+#endif
diff --git a/pcbnew/scripting/plugins.i b/pcbnew/scripting/plugins.i
new file mode 100644
index 0000000..7e7dcb7
--- /dev/null
+++ b/pcbnew/scripting/plugins.i
@@ -0,0 +1,35 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2013 NBEE Embedded Systems SL, Miguel Angel Ajo <miguelangel@ajo.es>
+ * Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+#include <scripting/pcbnew_footprint_wizards.h>
+%}
+
+class PYTHON_FOOTPRINT_WIZARDS
+{
+public:
+ static void register_wizard(PyObject *wizard);
+ static void deregister_wizard(PyObject *wizard);
+
+};
diff --git a/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py b/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py
new file mode 100644
index 0000000..8526b45
--- /dev/null
+++ b/pcbnew/scripting/plugins/FPC_(SMD_type)_footprintwizard.py
@@ -0,0 +1,156 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+from __future__ import division
+import pcbnew
+
+import HelpfulFootprintWizardPlugin as HFPW
+
+
+class FPC_FootprintWizard(HFPW.HelpfulFootprintWizardPlugin):
+
+ def GetName(self):
+ return "FPC (SMT connector)"
+
+ def GetDescription(self):
+ return "FPC (SMT connector) Footprint Wizard"
+
+ def GetValue(self):
+ pins = self.parameters["Pads"]["*n"]
+ return "FPC_%d" % pins
+
+ def GenerateParameterList(self):
+ self.AddParam( "Pads", "n", self.uNatural, 40 )
+ self.AddParam( "Pads", "pitch", self.uMM, 0.5 )
+ self.AddParam( "Pads", "width", self.uMM, 0.25 )
+ self.AddParam( "Pads", "height", self.uMM, 1.6)
+ self.AddParam( "Shield", "shield_to_pad", self.uMM, 1.6 )
+ self.AddParam( "Shield", "from_top", self.uMM, 1.3 )
+ self.AddParam( "Shield", "width", self.uMM, 1.5 )
+ self.AddParam( "Shield", "height", self.uMM, 2 )
+
+
+ # build a rectangular pad
+ def smdRectPad(self,module,size,pos,name):
+ pad = pcbnew.D_PAD(module)
+ pad.SetSize(size)
+ pad.SetShape(pcbnew.PAD_SHAPE_RECT)
+ pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
+ pad.SetLayerSet( pad.SMDMask() )
+ pad.SetPos0(pos)
+ pad.SetPosition(pos)
+ pad.SetPadName(name)
+ return pad
+
+ def CheckParameters(self):
+ p = self.parameters
+ self.CheckParamInt( "Pads", "*n" ) # not internal units preceded by "*"
+
+
+ def BuildThisFootprint(self):
+ p = self.parameters
+ pad_count = int(p["Pads"]["*n"])
+ pad_width = p["Pads"]["width"]
+ pad_height = p["Pads"]["height"]
+ pad_pitch = p["Pads"]["pitch"]
+ shl_width = p["Shield"]["width"]
+ shl_height = p["Shield"]["height"]
+ shl_to_pad = p["Shield"]["shield_to_pad"]
+ shl_from_top = p["Shield"]["from_top"]
+
+ offsetX = pad_pitch * ( pad_count-1 ) / 2
+ size_pad = pcbnew.wxSize( pad_width, pad_height )
+ size_shld = pcbnew.wxSize(shl_width, shl_height)
+ size_text = self.GetTextSize() # IPC nominal
+
+ # Gives a position and size to ref and value texts:
+ textposy = pad_height/2 + pcbnew.FromMM(1) + self.GetTextThickness()
+ self.draw.Reference( 0, textposy, size_text )
+
+ textposy = textposy + size_text + self.GetTextThickness()
+ self.draw.Value( 0, textposy, size_text )
+
+ # create a pad array and add it to the module
+ for n in range ( 0, pad_count ):
+ xpos = pad_pitch*n - offsetX
+ pad = self.smdRectPad(self.module,size_pad, pcbnew.wxPoint(xpos,0),str(n+1))
+ self.module.Add(pad)
+
+
+ # Mechanical shield pads: left pad and right pad
+ xpos = -shl_to_pad-offsetX
+ pad_s0_pos = pcbnew.wxPoint(xpos,shl_from_top)
+ pad_s0 = self.smdRectPad(self.module, size_shld, pad_s0_pos, "0")
+ xpos = (pad_count-1) * pad_pitch+shl_to_pad - offsetX
+ pad_s1_pos = pcbnew.wxPoint(xpos,shl_from_top)
+ pad_s1 = self.smdRectPad(self.module, size_shld, pad_s1_pos, "0")
+
+ self.module.Add(pad_s0)
+ self.module.Add(pad_s1)
+
+ # add footprint outline
+ linewidth = self.draw.GetLineTickness()
+ margin = linewidth
+
+ # upper line
+ posy = -pad_height/2 - linewidth/2 - margin
+ xstart = - pad_pitch*0.5-offsetX
+ xend = pad_pitch * pad_count + xstart;
+ self.draw.Line( xstart, posy, xend, posy )
+
+ # lower line
+ posy = pad_height/2 + linewidth/2 + margin
+ self.draw.Line(xstart, posy, xend, posy)
+
+ # around left mechanical pad (the outline around right pad is mirrored/y axix)
+ yend = pad_s0_pos.y + shl_height/2 + margin
+ self.draw.Line(xstart, posy, xstart, yend)
+ self.draw.Line(-xstart, posy, -xstart, yend)
+
+ posy = yend
+ xend = pad_s0_pos.x - (shl_width/2 + linewidth + margin*2)
+ self.draw.Line(xstart, posy, xend, posy)
+
+ # right pad side
+ self.draw.Line(-xstart, posy, -xend, yend)
+
+ # vertical segment at left of the pad
+ xstart = xend
+ yend = posy - (shl_height + linewidth + margin*2)
+ self.draw.Line(xstart, posy, xend, yend)
+
+ # right pad side
+ self.draw.Line(-xstart, posy, -xend, yend)
+
+ # horizontal segment above the pad
+ xstart = xend
+ xend = - pad_pitch*0.5-offsetX
+ posy = yend
+ self.draw.Line(xstart, posy, xend, yend)
+
+ # right pad side
+ self.draw.Line(-xstart, posy,-xend, yend)
+
+ # vertical segment above the pad
+ xstart = xend
+ yend = -pad_height/2 - linewidth/2 - margin
+ self.draw.Line(xstart, posy, xend, yend)
+
+ # right pad side
+ self.draw.Line(-xstart, posy, -xend, yend)
+
+
+FPC_FootprintWizard().register()
diff --git a/pcbnew/scripting/plugins/FootprintWizardDrawingAids.py b/pcbnew/scripting/plugins/FootprintWizardDrawingAids.py
new file mode 100644
index 0000000..058fe1e
--- /dev/null
+++ b/pcbnew/scripting/plugins/FootprintWizardDrawingAids.py
@@ -0,0 +1,523 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+from __future__ import division
+
+import pcbnew
+import math
+
+
+class FootprintWizardDrawingAids:
+ """
+ Collection of handy functions to simplify drawing shapes from within
+ footprint wizards
+
+ A "drawing context" is provided which can be used to set and retain
+ settings such as line tickness and layer
+ """
+
+ # directions (in degrees, compass-like)
+ dirN = 0
+ dirNE = 45
+ dirE = 90
+ dirSE = 135
+ dirS = 180
+ dirSW = 225
+ dirW = 270
+ dirNW = 315
+
+ # flip constants
+ flipNone = 0
+ flipX = 1 # flip X values, i.e. about Y
+ flipY = 2 # flip Y valuersabout X
+ flipBoth = 3
+
+ xfrmIDENTITY = [1, 0, 0, 0, 1, 0] # no transform
+
+ # these values come from our KiCad Library Convention 0.11
+ defaultLineThickness = pcbnew.FromMM(0.15)
+
+ def DefaultGraphicLayer(self):
+ return pcbnew.F_SilkS
+
+ def DefaultTextValueLayer(self):
+ return pcbnew.F_Fab
+
+ def __init__(self, module):
+ self.module = module
+ # drawing context defaults
+ self.dc = {
+ 'layer': self.DefaultGraphicLayer(),
+ 'lineThickness': self.defaultLineThickness,
+ 'transforms': [],
+ 'transform': self.xfrmIDENTITY
+ }
+
+ def PushTransform(self, mat):
+ """
+ Add a transform to the top of the stack and recompute the
+ overall transform
+ """
+ self.dc['transforms'].append(mat)
+ self.RecomputeTransforms()
+
+ def PopTransform(self, num=1):
+ """
+ Remove a transform from the top of the stack and recompute the
+ overall transform
+ """
+
+ for i in range(num):
+ mat = self.dc['transforms'].pop()
+ self.RecomputeTransforms()
+ return mat
+
+ def ResetTransform(self):
+ """
+ Reset the transform stack to the identity matrix
+ """
+ self.dc['transforms'] = []
+ self.RecomputeTransforms()
+
+ def _ComposeMatricesWithIdentity(self, mats):
+ """
+ Compose a sequence of matrices together by sequential
+ pre-mutiplciation with the identity matrix
+ """
+
+ x = self.xfrmIDENTITY
+
+ for mat in mats:
+ #precompose with each transform in turn
+ x = [
+ x[0] * mat[0] + x[1] * mat[3],
+ x[0] * mat[1] + x[1] * mat[4],
+ x[0] * mat[2] + x[1] * mat[5] + x[2],
+ x[3] * mat[0] + x[4] * mat[3],
+ x[3] * mat[1] + x[4] * mat[4],
+ x[3] * mat[2] + x[4] * mat[5] + x[5]]
+
+ return x
+
+ def RecomputeTransforms(self):
+ """
+ Re-compute the transform stack into a single transform and
+ store in the DC
+ """
+ self.dc['transform'] = self._ComposeMatricesWithIdentity(
+ self.dc['transforms'])
+
+ def TransformTranslate(self, x, y, push=True):
+ """
+ Set up and return a transform matrix representing a translartion
+ optionally pushing onto the stack
+
+ ( 1 0 x )
+ ( 0 1 y )
+ """
+ mat = [1, 0, x, 0, 1, y]
+
+ if push:
+ self.PushTransform(mat)
+ return mat
+
+ def TransformFlipOrigin(self, flip, push=True):
+ """
+ Set up and return a transform matrix representing a horizontal,
+ vertical or both flip about the origin
+ """
+ mat = None
+ if flip == self.flipX:
+ mat = [-1, 0, 0, 0, 1, 0]
+ elif flip == self.flipY:
+ mat = [1, 0, 0, 0, -1, 0]
+ elif flip == self.flipBoth:
+ mat = [-1, 0, 0, 0, -1, 0]
+ elif flip == self.flipNone:
+ mat = self.xfrmIDENTITY
+ else:
+ raise ValueError
+
+ if push:
+ self.PushTransform(mat)
+ return mat
+
+ def TransformFlip(self, x, y, flip=flipNone, push=True):
+ """
+ Set up and return a transform matrix representing a horizontal,
+ vertical or both flip about a point (x,y)
+
+ This is performed by a translate-to-origin, flip, translate-
+ back sequence
+ """
+ mats = [self.TransformTranslate(x, y, push=False),
+ self.TransformFlipOrigin(flip, push=False),
+ self.TransformTranslate(-x, -y, push=False)]
+
+ #distill into a single matrix
+ mat = self._ComposeMatricesWithIdentity(mats)
+
+ if push:
+ self.PushTransform(mat)
+ return mat
+
+ def TransformRotationOrigin(self, rot, push=True):
+ """
+ Set up and return a transform matrix representing a rotation
+ about the origin, and optionally push onto the stack
+
+ ( cos(t) -sin(t) 0 )
+ ( sin(t) cos(t) 0 )
+ """
+ rads = rot * math.pi / 180
+ mat = [math.cos(rads), -math.sin(rads), 0,
+ math.sin(rads), math.cos(rads), 0]
+
+ if push:
+ self.PushTransform(mat)
+ return mat
+
+ def TransformRotation(self, x, y, rot, push=True):
+ """
+ Set up and return a transform matrix representing a rotation
+ about the point (x,y), and optionally push onto the stack
+
+ This is performed by a translate-to-origin, rotate, translate-
+ back sequence
+ """
+
+ mats = [self.TransformTranslate(x, y, push=False),
+ self.TransformRotationOrigin(rot, push=False),
+ self.TransformTranslate(-x, -y, push=False)]
+
+ #distill into a single matrix
+ mat = self._ComposeMatricesWithIdentity(mats)
+
+ if push:
+ self.PushTransform(mat)
+ return mat
+
+ def TransformScaleOrigin(self, sx, sy=None, push=True):
+ """
+ Set up and return a transform matrix representing a scale about
+ the origin, and optionally push onto the stack
+
+ ( sx 0 0 )
+ ( 0 sy 0 )
+ """
+
+ if sy is None:
+ sy = sx
+
+ mat = [sx, 0, 0, 0, sy, 0]
+
+ if push:
+ self.PushTransform(mat)
+ return mat
+
+ def TransformPoint(self, x, y, mat=None):
+ """
+ Return a point (x, y) transformed by the given matrix, or if
+ that is not given, the drawing context transform
+ """
+
+ if not mat:
+ mat = self.dc['transform']
+
+ return pcbnew.wxPoint(x * mat[0] + y * mat[1] + mat[2],
+ x * mat[3] + y * mat[4] + mat[5])
+
+ def SetLineTickness(self, lineThickness):
+ """
+ Set the current pen lineThickness used for subsequent drawing
+ operations
+ """
+ self.dc['lineThickness'] = lineThickness
+
+ def GetLineTickness(self):
+ """
+ Get the current drawing context line tickness
+ """
+ return self.dc['lineThickness']
+
+ def SetLayer(self, layer):
+ """
+ Set the current drawing layer, used for subsequent drawing
+ operations
+ """
+ self.dc['layer'] = layer
+
+ def GetLayer(self):
+ """
+ return the current drawing layer, used drawing operations
+ """
+ return self.dc['layer']
+
+ def Line(self, x1, y1, x2, y2):
+ """
+ Draw a line from (x1, y1) to (x2, y2)
+ """
+ outline = pcbnew.EDGE_MODULE(self.module)
+ outline.SetWidth(self.GetLineTickness())
+ outline.SetLayer(self.GetLayer())
+ outline.SetShape(pcbnew.S_SEGMENT)
+ start = self.TransformPoint(x1, y1)
+ end = self.TransformPoint(x2, y2)
+ outline.SetStartEnd(start, end)
+ self.module.Add(outline)
+
+ def Circle(self, x, y, r, filled=False):
+ """
+ Draw a circle at (x,y) of radius r
+ If filled is true, the thickness and radius of the line will be set
+ such that the circle appears filled
+ """
+ circle = pcbnew.EDGE_MODULE(self.module)
+ start = self.TransformPoint(x, y)
+
+ if filled:
+ circle.SetWidth(r)
+ end = self.TransformPoint(x, y + r/2)
+ else:
+ circle.SetWidth(self.dc['lineThickness'])
+ end = self.TransformPoint(x, y + r)
+
+ circle.SetLayer(self.dc['layer'])
+ circle.SetShape(pcbnew.S_CIRCLE)
+ circle.SetStartEnd(start, end)
+ self.module.Add(circle)
+
+ def Arc(self, cx, cy, sx, sy, a):
+ """
+ Draw an arc based on centre, start and angle
+
+ The transform matrix is applied
+
+ Note that this won't work properly if the result is not a
+ circular arc (eg a horzontal scale)
+ """
+ circle = pcbnew.EDGE_MODULE(self.module)
+ circle.SetWidth(self.dc['lineThickness'])
+
+ center = self.TransformPoint(cx, cy)
+ start = self.TransformPoint(sx, sy)
+
+ circle.SetLayer(self.dc['layer'])
+ circle.SetShape(pcbnew.S_ARC)
+
+ # check if the angle needs to be reverse (a flip scaling)
+ if cmp(self.dc['transform'][0], 0) != cmp(self.dc['transform'][4], 0):
+ a = -a
+
+ circle.SetAngle(a)
+ circle.SetStartEnd(center, start)
+ self.module.Add(circle)
+
+ # extends from (x1,y1) right
+ def HLine(self, x, y, l):
+ """
+ Draw a horizontal line from (x,y), rightwards
+ """
+ self.Line(x, y, x + l, y)
+
+ def VLine(self, x, y, l):
+ """
+ Draw a vertical line from (x1,y1), downwards
+ """
+ self.Line(x, y, x, y + l)
+
+ def Polyline(self, pts, mirrorX=None, mirrorY=None):
+ """
+ Draw a polyline, optinally mirroring around the given points
+ """
+
+ def _PolyLineInternal(pts):
+ if len(pts) < 2:
+ return
+
+ for i in range(0, len(pts) - 1):
+ self.Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1])
+
+ _PolyLineInternal(pts) # original
+
+ if mirrorX is not None:
+ self.TransformFlip(mirrorX, 0, self.flipX)
+ _PolyLineInternal(pts)
+ self.PopTransform()
+
+ if mirrorY is not None:
+ self.TransformFlipOrigin(0, mirrorY, self.flipY)
+ _PolyLineInternal(pts)
+ self.PopTransform()
+
+ if mirrorX is not None and mirrorY is not None:
+ self.TransformFlip(mirrorX, mirrorY, self.flipBoth) # both
+ _PolyLineInternal(pts)
+ self.PopTransform()
+
+ def Reference(self, x, y, size, orientation_degree = 0):
+ """
+ Draw the module's reference as the given point.
+
+ The actual setting of the reference is not done in this drawing
+ aid - that is up to the wizard
+ """
+
+ text_size = pcbnew.wxSize(size, size)
+
+ self.module.Reference().SetPos0(self.TransformPoint(x, y))
+ self.module.Reference().SetTextPosition(
+ self.module.Reference().GetPos0())
+ self.module.Reference().SetSize(text_size)
+ self.module.Reference().SetOrientation(orientation_degree*10) # internal angles are in 0.1 deg
+
+ def Value(self, x, y, size, orientation_degree = 0):
+ """
+ As for references, draw the module's value
+ """
+ text_size = pcbnew.wxSize(size, size)
+
+ self.module.Value().SetPos0(self.TransformPoint(x, y))
+ self.module.Value().SetTextPosition(self.module.Value().GetPos0())
+ self.module.Value().SetSize(text_size)
+ self.module.Value().SetLayer(self.DefaultTextValueLayer())
+ self.module.Value().SetOrientation(orientation_degree*10) # internal angles are in 0.1 deg
+
+ def Box(self, x, y, w, h):
+ """
+ Draw a rectangular box, centred at (x,y), with given width and
+ height
+ """
+
+ pts = [[x - w/2, y - h/2], # left
+ [x + w/2, y - h/2], # right
+ [x + w/2, y + h/2], # bottom
+ [x - w/2, y + h/2], # top
+ [x - w/2, y - h/2]] # close
+
+ self.Polyline(pts)
+
+ def NotchedCircle(self, x, y, r, notch_w, notch_h, rotate=0):
+ """
+ Circle radus r centred at (x, y) with a raised or depressed notch
+ at the top
+ Notch height is measured from the top of the circle radius
+ """
+
+ self.TransformRotation(x, y, rotate)
+
+ # find the angle where the notch vertical meets the circle
+ angle_intercept = math.asin(notch_w/(2 * r))
+
+ # and find the co-ords of this point
+ sx = math.sin(angle_intercept) * r
+ sy = -math.cos(angle_intercept) * r
+
+ # NOTE: this may be out by a factor of ten one day
+ arc_angle = (math.pi * 2 - angle_intercept * 2) * (1800/math.pi)
+
+ self.Arc(x,y, sx, sy, arc_angle)
+
+ pts = [[sx, sy],
+ [sx, -r - notch_h],
+ [-sx, -r - notch_h],
+ [-sx, sy]]
+
+ self.Polyline(pts)
+ self.PopTransform()
+
+ def NotchedBox(self, x, y, w, h, notchW, notchH, rotate=0):
+ """
+ Draw a box with a notch in the top edge
+ """
+
+ self.TransformRotation(x, y, rotate)
+
+ # limit to half the overall width
+ notchW = min(x + w/2, notchW)
+
+ # draw notch
+ self.Polyline([ # three sides of box
+ (x - w/2, y - h/2),
+ (x - w/2, y + h/2),
+ (x + w/2, y + h/2),
+ (x + w/2, y - h/2),
+ # the notch
+ (notchW/2, y - h/2),
+ (notchW/2, y - h/2 + notchH),
+ (-notchW/2, y - h/2 + notchH),
+ (-notchW/2, y - h/2),
+ (x - w/2, y - h/2)
+ ])
+
+ self.PopTransform()
+
+ def BoxWithDiagonalAtCorner(self, x, y, w, h,
+ setback=pcbnew.FromMM(1.27), flip=flipNone):
+ """
+ Draw a box with a diagonal at the top left corner
+ """
+
+ self.TransformFlip(x, y, flip, push=True)
+
+ pts = [[x - w/2 + setback, y - h/2],
+ [x - w/2, y - h/2 + setback],
+ [x - w/2, y + h/2],
+ [x + w/2, y + h/2],
+ [x + w/2, y - h/2],
+ [x - w/2 + setback, y - h/2]]
+
+ self.Polyline(pts)
+
+ self.PopTransform()
+
+ def BoxWithOpenCorner(self, x, y, w, h,
+ setback=pcbnew.FromMM(1.27), flip=flipNone):
+ """
+ Draw a box with an opening at the top left corner
+ """
+
+ self.TransformTranslate(x, y)
+ self.TransformFlipOrigin(flip)
+
+ pts = [[- w/2, - h/2 + setback],
+ [- w/2, + h/2],
+ [+ w/2, + h/2],
+ [+ w/2, - h/2],
+ [- w/2 + setback, - h/2]]
+
+ self.Polyline(pts)
+
+ self.PopTransform(num=2)
+
+ def MarkerArrow(self, x, y, direction=dirN, width=pcbnew.FromMM(1)):
+ """
+ Draw a marker arrow facing in the given direction, with the
+ point at (x,y)
+
+ Direction of 0 is north
+ """
+
+ self.TransformTranslate(x, y)
+ self.TransformRotationOrigin(direction)
+
+ pts = [[0, 0],
+ [width / 2, width / 2],
+ [-width / 2, width / 2],
+ [0, 0]]
+
+ self.Polyline(pts)
+ self.PopTransform(2)
diff --git a/pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py b/pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py
new file mode 100644
index 0000000..90d2498
--- /dev/null
+++ b/pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py
@@ -0,0 +1,330 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+import pcbnew
+import math
+import FootprintWizardDrawingAids
+
+
+class FootprintWizardParameterManager:
+ """
+ Functions for helpfully managing parameters to a KiCAD Footprint
+ Wizard.
+
+ Abstracts away from whatever structure is used by pcbnew's footprint
+ wizard class
+ """
+
+ def __init__(self):
+ self.parameters = {}
+ self.GenerateParameterList()
+
+ def GenerateParameterList(self):
+ """
+ Construct parameters here, or leave out to have no parameters
+ """
+ pass
+
+ def CheckParameters(self):
+ """
+ Implement this to make checks on parameter values, filling
+ parameter_errors (or using the checker routines)
+
+ Subclasses can implment their own and override the parent
+ defaults and add new ones
+ """
+ pass
+
+ uMM = 1
+ uMils = 2
+ uNatural = 3
+ uBool = 4
+ uString = 5
+
+ def AddParam(self, section, param, unit, default, hint=''):
+ """
+ Add a parameter with some properties.
+
+ TODO: Hints are not supported, as there is as yet nowhere to
+ put them in the KiCAD interface
+ """
+ error = ""
+ val = None
+ if unit == self.uMM:
+ val = pcbnew.FromMM(default)
+ elif unit == self.uMils:
+ val = pcbnew.FromMils(default)
+ elif unit == self.uNatural:
+ val = default
+ elif unit == self.uString:
+ val = str(default)
+ elif unit == self.uBool:
+ val = "True" if default else "False" # ugly stringing
+ else:
+ error = "Warning: Unknown unit type: %s" % unit
+ return error
+
+ if unit in [self.uNatural, self.uBool, self.uString]:
+ param = "*%s" % param # star prefix for natural
+
+ if section not in self.parameters:
+ if not hasattr(self, 'page_order'):
+ self.page_order = []
+ self.page_order.append(section)
+ self.parameters[section] = {}
+ if not hasattr(self, 'parameter_order'):
+ self.parameter_order = {}
+ self.parameter_order[section] = []
+
+ self.parameters[section][param] = val
+ self.parameter_order[section].append(param)
+
+ return error
+
+
+ def _PrintParameterTable(self):
+ """
+ Pretty-print the parameters we have
+ """
+ message = ""
+
+ for name, section in self.parameters.iteritems():
+ message += " %s:\n" % name
+
+ for key, value in section.iteritems():
+ unit = ""
+ if ((type(value) is int or type(value) is float)
+ and not "*" in key):
+ unit = "mm"
+
+ if "*" in key:
+ key = key[1:]
+ else:
+ value = pcbnew.ToMM(value)
+
+ message += " %s: %s%s\n" % (key, value, unit)
+
+ return message
+
+
+ def _ParametersHaveErrors(self):
+ """
+ Return true if we discovered errors during parameter processing
+ """
+
+ for name, section in self.parameter_errors.iteritems():
+ for k, v in section.iteritems():
+ if v:
+ return True
+
+ return False
+
+ def _PrintParameterErrors(self):
+ """
+ Pretty-print parameters with errors
+ """
+ errors = ""
+
+ for name, section in self.parameter_errors.iteritems():
+ printed_section = False
+
+ for key, value in section.iteritems():
+ if value:
+ if not printed_section:
+ errors += " %s:" % name
+
+ errors += " %s: %s (have %s)\n" % (
+ key, value, self.parameters[name][key])
+
+ return errors
+
+ def ProcessParameters(self):
+ """
+ Make sure the parameters we have meet whatever expectations the
+ footprint wizard has of them
+ """
+
+ self.ClearErrors()
+ self.CheckParameters()
+
+ if self._ParametersHaveErrors():
+ return False
+
+ return True
+
+ #################################################################
+ # PARAMETER CHECKERS
+ #################################################################
+
+ def CheckParamInt(self, section, param, min_value=1,
+ max_value=None, is_multiple_of=1):
+ """
+ Make sure a parameter can be made into an int, and enforce
+ limits if required
+ """
+
+ try:
+ self.parameters[section][param] = (
+ int(self.parameters[section][param]))
+ except ValueError:
+ self.parameter_errors[section][param] = (
+ "Must be a valid integer")
+ return
+
+ if min_value is not None and (
+ self.parameters[section][param] < min_value):
+ self.parameter_errors[section][param] = (
+ "Must be greater than or equal to %d" % (min_value))
+ return
+
+ if max_value is not None and (
+ self.parameters[section][param] > max_value):
+ self.parameter_errors[section][param] = (
+ "Must be less than or equal to %d" % (max_value))
+ return
+
+ if is_multiple_of > 1 and (
+ self.parameters[section][param] % is_multiple_of) > 0:
+ self.parameter_errors[section][param] = (
+ "Must be a multiple of %d" % is_multiple_of)
+ return
+
+ return
+
+ def CheckParamBool(self, section, param):
+ """
+ Make sure a parameter looks like a boolean, convert to native
+ boolean type if so
+ """
+ if str(self.parameters[section][param]).lower() in [
+ "true", "t", "y", "yes", "on", "1", "1.0"]:
+ self.parameters[section][param] = True
+ return
+ elif str(self.parameters[section][param]).lower() in [
+ "false", "f", "n", "no", "off", "0", "0.0"]:
+ self.parameters[section][param] = False
+ return
+
+ self.parameter_errors[section][param] = "Must be boolean (true/false)"
+ return
+
+
+class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
+ FootprintWizardParameterManager):
+ """
+ A class to simplify many aspects of footprint creation, leaving only
+ the foot-print specific routines to the wizards themselves
+
+ Generally, you need to implement:
+ GetReference()
+ GetValue()
+ GenerateParameterList()
+ CheckParameters()
+ BuildThisFootprint()
+ GetName()
+ GetDescription()
+ """
+ def __init__(self):
+ pcbnew.FootprintWizardPlugin.__init__(self)
+ FootprintWizardParameterManager.__init__(self)
+
+ self.name = self.GetName()
+ self.decription = self.GetDescription()
+ self.image = self.GetImage()
+
+ def GetValue(self):
+ raise NotImplementedError
+
+ # this value come from our KiCad Library Convention 0.11
+ def GetReferencePrefix(self):
+ return "REF"
+
+ def GetImage(self):
+ return ""
+
+ def GetTextSize(self):
+ """
+ IPC nominal
+ """
+ return pcbnew.FromMM(1.2)
+
+ def GetTextThickness(self):
+ """
+ Thicker than IPC guidelines (10% of text height = 0.12mm)
+ as 5 wires/mm is a common silk screen limitation
+ """
+ return pcbnew.FromMM(0.15)
+
+ def SetModule3DModel(self):
+ """
+ Set a 3D model for the module
+
+ Default is to do nothing, you need to implement this if you have
+ a model to set
+
+ FIXME: This doesn't seem to be enabled yet?
+ """
+ pass
+
+ def BuildThisFootprint(self):
+ """
+ Draw the footprint.
+
+ This is specific to each footprint class, you need to implment
+ this to draw what you want
+ """
+ raise NotImplementedError
+
+ def BuildFootprint( self ):
+ """
+ Actually make the footprint. We defer all but the setup to
+ the implementing class
+ """
+
+ self.buildmessages = ""
+
+ self.module = pcbnew.MODULE(None) # create a new module
+ # do it first, so if we return early, we don't segfault KiCad
+
+ if not self.ProcessParameters():
+ self.buildmessages = "Cannot build footprint: Parameters have errors:\n"
+ self.buildmessages += self._PrintParameterErrors()
+ return
+
+ self.buildmessages = ("Building new %s footprint with the following parameters:\n"
+ % self.name)
+
+ self.buildmessages += self._PrintParameterTable()
+
+ self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(
+ self.module)
+
+ self.module.SetValue(self.GetValue())
+ self.module.SetReference("%s**" % self.GetReferencePrefix())
+
+ fpid = pcbnew.FPID(self.module.GetValue()) # the name in library
+ self.module.SetFPID(fpid)
+
+ self.SetModule3DModel() # add a 3d module if specified
+
+ thick = self.GetTextThickness()
+
+ self.module.Reference().SetThickness(thick)
+ self.module.Value().SetThickness(thick)
+
+ self.BuildThisFootprint() # implementer's build function
+
+ return
diff --git a/pcbnew/scripting/plugins/PadArray.py b/pcbnew/scripting/plugins/PadArray.py
new file mode 100644
index 0000000..5908d38
--- /dev/null
+++ b/pcbnew/scripting/plugins/PadArray.py
@@ -0,0 +1,275 @@
+# PadArray.py
+#
+# Copyright 2014 john <john@johndev>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+#
+
+from __future__ import division
+
+import math
+import pcbnew
+
+class PadMaker:
+ """
+ Useful construction functions for common types of pads
+ """
+
+ def __init__(self, module):
+ self.module = module
+
+ def THPad(self, Vsize, Hsize, drill, shape=pcbnew.PAD_SHAPE_OVAL, rot_degree = 0):
+ pad = pcbnew.D_PAD(self.module)
+ pad.SetSize(pcbnew.wxSize(Hsize, Vsize))
+ pad.SetShape(shape)
+ pad.SetAttribute(pcbnew.PAD_ATTRIB_STANDARD)
+ pad.SetLayerSet(pad.StandardMask())
+ pad.SetDrillSize(pcbnew.wxSize(drill, drill))
+ pad.SetOrientation(rot_degree*10) # rotation is in 0.1 degrees
+
+ return pad
+
+ def THRoundPad(self, size, drill):
+ pad = self.THPad(size, size, drill, shape=pcbnew.PAD_SHAPE_CIRCLE)
+ return pad
+
+ def NPTHRoundPad(self, drill):
+ pad = pcbnew.D_PAD(self.module)
+ pad.SetSize(pcbnew.wxSize(drill, drill))
+ pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
+ pad.SetAttribute(pcbnew.PAD_ATTRIB_HOLE_NOT_PLATED)
+ pad.SetLayerSet(pad.UnplatedHoleMask())
+ pad.SetDrillSize(pcbnew.wxSize(drill, drill))
+ return pad
+
+ def SMDPad(self, Vsize, Hsize, shape=pcbnew.PAD_SHAPE_RECT, rot_degree=0):
+ pad = pcbnew.D_PAD(self.module)
+ pad.SetSize(pcbnew.wxSize(Hsize, Vsize))
+ pad.SetShape(shape)
+ pad.SetAttribute(pcbnew.PAD_ATTRIB_SMD)
+ pad.SetLayerSet(pad.SMDMask())
+ pad.SetOrientation(rot_degree*10) # rotation is in 0.1 degrees
+
+ return pad
+
+ def SMTRoundPad(self, size):
+ pad = self.SMDPad(size, size, shape=pcbnew.PAD_SHAPE_CIRCLE)
+ return pad
+
+
+class PadArray:
+
+ def __init__(self):
+ self.firstPadNum = 1
+ self.pinNames = None
+ self.firstPad = None
+
+ def SetPinNames(self, pinNames):
+ """
+ Set a name for all the pins
+ """
+ self.pinNames = pinNames
+
+ def SetFirstPadType(self, firstPad):
+ self.firstPad = firstPad
+
+ def SetFirstPadInArray(self, fpNum):
+ self.firstPadNum = fpNum
+
+ def AddPad(self, pad):
+ self.pad.GetParent().Add(pad)
+
+ def GetPad(self, is_first_pad, pos):
+ if (self.firstPad and is_first_pad):
+ pad = self.firstPad
+ else:
+ pad = self.pad
+
+ # create a new pad with same characteristics
+ pad = pad.Duplicate()
+ pad.SetPos0(pos)
+ pad.SetPosition(pos)
+
+ return pad
+
+ def GetName(self, *args, **kwargs):
+
+ if self.pinNames is None:
+ return self.NamingFunction(*args, **kwargs)
+
+ return self.pinNames
+
+ def NamingFunction(self, *args, **kwargs):
+ """
+ Implement this as needed for each array type
+ """
+ raise NotImplementedError;
+
+
+class PadGridArray(PadArray):
+
+ def __init__(self, pad, nx, ny, px, py, centre=pcbnew.wxPoint(0, 0)):
+ PadArray.__init__(self)
+ # this pad is more of a "context", we will use it as a source of
+ # pad data, but not actually add it
+ self.pad = pad
+ self.nx = int(nx)
+ self.ny = int(ny)
+ self.px = px
+ self.py = py
+ self.centre = centre
+
+ # handy utility function 1 - A, 2 - B, 26 - AA, etc
+ # aIndex = 0 for 0 - A
+ # alphabet = set of allowable chars if not A-Z,
+ # eg ABCDEFGHJKLMNPRTUVWY for BGA
+ def AlphaNameFromNumber(self, n, aIndex=1,
+ alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
+
+ div, mod = divmod(n - aIndex, len(alphabet))
+ alpha = alphabet[mod]
+
+ if div > 0:
+ return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha
+
+ return alpha
+
+ # right to left, top to bottom
+ def NamingFunction(self, x, y):
+ return self.firstPadNum + (self.nx * y + x)
+
+ #relocate the pad and add it as many times as we need
+ def AddPadsToModule(self, dc):
+
+ pin1posX = self.centre.x - self.px * (self.nx - 1) / 2
+ pin1posY = self.centre.y - self.py * (self.ny - 1) / 2
+
+ for x in range(0, self.nx):
+ posX = pin1posX + (x * self.px)
+
+ for y in range(self.ny):
+ posY = pin1posY + (self.py * y)
+ pos = dc.TransformPoint(posX, posY)
+ pad = self.GetPad(x == 0 and y == 0, pos)
+ pad.SetPadName(self.GetName(x,y))
+ self.AddPad(pad)
+
+
+class PadZGridArray(PadArray):
+
+ def __init__(self, pad, pad_count, line_count, line_pitch,
+ pad_pitch, centre=pcbnew.wxPoint(0, 0)):
+ PadArray.__init__(self)
+ # this pad is more of a "context", we will use it as a source of
+ # pad data, but not actually add it
+ self.pad = pad
+ self.pad_count = int(pad_count)
+ self.line_count = int(line_count)
+ self.line_pitch = line_pitch
+ self.pad_pitch = pad_pitch
+ self.centre = centre
+
+
+ # right to left, top to bottom
+ def NamingFunction(self, pad_pos):
+ return self.firstPadNum + pad_pos
+
+ #relocate the pad and add it as many times as we need
+ def AddPadsToModule(self, dc):
+
+ pin1posX = self.centre.x - self.pad_pitch * (self.pad_count - 1) / 2
+ pin1posY = self.centre.y + self.line_pitch * (self.line_count - 1) / 2
+ line = 0
+
+ for padnum in range(0, self.pad_count):
+ posX = pin1posX + (padnum * self.pad_pitch)
+ posY = pin1posY - (self.line_pitch * line)
+
+ pos = dc.TransformPoint(posX, posY)
+ pad = self.GetPad(padnum == 0, pos)
+ pad.SetPadName(self.GetName(padnum))
+ self.AddPad(pad)
+
+ line += 1
+
+ if line >= self.line_count:
+ line = 0
+
+class PadLineArray(PadGridArray):
+
+ def __init__(self, pad, n, pitch, isVertical,
+ centre=pcbnew.wxPoint(0, 0)):
+
+ if isVertical:
+ PadGridArray.__init__(self, pad, 1, n, 0, pitch, centre)
+ else:
+ PadGridArray.__init__(self, pad, n, 1, pitch, 0, centre)
+
+class PadCircleArray(PadArray):
+
+ def __init__(self, pad, n, r, angle_offset=0, centre=pcbnew.wxPoint(0, 0),
+ clockwise=True):
+ PadArray.__init__(self)
+ # this pad is more of a "context", we will use it as a source of
+ # pad data, but not actually add it
+ self.pad = pad
+ self.n = int(n)
+ self.r = r
+ self.angle_offset = angle_offset
+ self.centre = centre
+ self.clockwise = clockwise
+
+ # around the circle, CW or CCW according to the flag
+ def NamingFunction(self, n):
+ return str(self.firstPadNum + n)
+
+ #relocate the pad and add it as many times as we need
+ def AddPadsToModule(self, dc):
+ for pin in range(0, self.n):
+ angle = self.angle_offset + (360 / self.n) * pin
+
+ if not self.clockwise:
+ angle = -angle
+
+ pos_x = math.sin(angle * math.pi / 180) * self.r
+ pos_y = -math.cos(angle * math.pi / 180) * self.r
+ pos = dc.TransformPoint(pos_x, pos_y)
+ pad = self.GetPad(pin == 0, pos)
+ pad.SetPadName(self.GetName(pin))
+ self.AddPad(pad)
+
+class PadCustomArray(PadArray):
+ """
+ Layout pads according to a custom array of [x,y] data
+ """
+
+ def __init__(self, pad, array):
+ PadArray.__init__(self)
+ self.pad = pad
+ self.array = array
+
+ def NamingFunction(self, n):
+ return str(self.firstPadNum + n)
+
+ #relocate the pad and add it as many times as we need
+ def AddPadsToModule(self, dc):
+
+ for i in range(len(self.array)):
+ pos = dc.TransformPoint(self.array[i][0], self.array[i][1])
+ pad = self.GetPad(i == 0, pos)
+ pad.SetPadName(self.GetName(i))
+ self.AddPad(pad)
diff --git a/pcbnew/scripting/plugins/__init__.py b/pcbnew/scripting/plugins/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/pcbnew/scripting/plugins/__init__.py
@@ -0,0 +1 @@
+
diff --git a/pcbnew/scripting/plugins/bga_wizard.py b/pcbnew/scripting/plugins/bga_wizard.py
new file mode 100644
index 0000000..ed3500f
--- /dev/null
+++ b/pcbnew/scripting/plugins/bga_wizard.py
@@ -0,0 +1,98 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+from __future__ import division
+import pcbnew
+
+import HelpfulFootprintWizardPlugin as HFPW
+import PadArray as PA
+
+
+class BGAPadGridArray(PA.PadGridArray):
+
+ def NamingFunction(self, n_x, n_y):
+ return "%s%d" % (
+ self.AlphaNameFromNumber(n_y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"),
+ n_x + 1)
+
+
+class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
+
+ def GetName(self):
+ return "BGA"
+
+ def GetDescription(self):
+ return "Ball Grid Array Footprint Wizard"
+
+ def GenerateParameterList(self):
+ self.AddParam("Pads", "pad pitch", self.uMM, 1)
+ self.AddParam("Pads", "pad size", self.uMM, 0.5)
+ self.AddParam("Pads", "row count", self.uNatural, 5)
+ self.AddParam("Pads", "column count", self.uNatural, 5)
+ self.AddParam("Pads", "outline x margin", self.uMM, 1)
+ self.AddParam("Pads", "outline y margin", self.uMM, 1)
+
+ def CheckParameters(self):
+ self.CheckParamInt("Pads", "*row count")
+ self.CheckParamInt("Pads", "*column count")
+
+ def GetValue(self):
+ pins = (self.parameters["Pads"]["*row count"]
+ * self.parameters["Pads"]["*column count"])
+
+ return "BGA_%d" % pins
+
+ def BuildThisFootprint(self):
+
+ pads = self.parameters["Pads"]
+
+ rows = pads["*row count"]
+ cols = pads["*column count"]
+ pad_size = pads["pad size"]
+ pad_size = pcbnew.wxSize(pad_size, pad_size)
+ pad_pitch = pads["pad pitch"]
+
+ # add in the pads
+ pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"])
+
+ pin1_pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2,
+ -((rows - 1) * pad_pitch) / 2)
+
+ array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch)
+ array.AddPadsToModule(self.draw)
+
+ #box
+ ssx = -pin1_pos.x + pads["outline x margin"]
+ ssy = -pin1_pos.y + pads["outline y margin"]
+
+ self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2,
+ pads["outline x margin"])
+
+ # Courtyard
+ cmargin = self.draw.GetLineTickness()
+ self.draw.SetLayer(pcbnew.F_CrtYd)
+ sizex = (ssx + cmargin) * 2
+ sizey = (ssy + cmargin) * 2
+ self.draw.Box(0, 0, sizex, sizey)
+
+ #reference and value
+ text_size = self.GetTextSize() # IPC nominal
+ ypos = ssy + text_size
+ self.draw.Value(0, ypos, text_size)
+ self.draw.Reference(0, -ypos, text_size)
+
+
+BGAWizard().register()
diff --git a/pcbnew/scripting/plugins/circular_pad_array_wizard.py b/pcbnew/scripting/plugins/circular_pad_array_wizard.py
new file mode 100644
index 0000000..0b2a280
--- /dev/null
+++ b/pcbnew/scripting/plugins/circular_pad_array_wizard.py
@@ -0,0 +1,83 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+from __future__ import division
+
+import math
+
+import pcbnew
+import HelpfulFootprintWizardPlugin as HFPW
+import PadArray as PA
+
+
+class circular_pad_array_wizard(HFPW.HelpfulFootprintWizardPlugin):
+
+ def GetName(self):
+ return "Circular Pad Array"
+
+ def GetDescription(self):
+ return "Circular array of pads"
+
+ def GenerateParameterList(self):
+
+ self.AddParam("Pads", "n", self.uNatural, 6)
+ self.AddParam("Pads", "pad width", self.uMM, 1.5)
+ self.AddParam("Pads", "drill", self.uMM, 1)
+ self.AddParam("Pads", "circle diameter", self.uMM, 5)
+ self.AddParam("Pads", "first pad angle", self.uNatural, 0)
+ self.AddParam("Pads", "number clockwise", self.uBool, True)
+ self.AddParam("Pads", "first pad number", self.uNatural, 1)
+
+ def CheckParameters(self):
+
+ self.CheckParamInt("Pads", "*n")
+ self.CheckParamInt("Pads", "*first pad number")
+ self.CheckParamBool("Pads", "*number clockwise")
+
+ def GetValue(self):
+ pins = self.parameters["Pads"]["*n"]
+ return "CPA_%d" % pins
+
+ def BuildThisFootprint(self):
+
+ prm = self.parameters['Pads']
+
+ pad_size = prm['pad width']
+
+ pad = PA.PadMaker(self.module).THPad(
+ prm['pad width'], prm['pad width'], prm['drill'])
+
+ array = PA.PadCircleArray(
+ pad, prm['*n'], prm['circle diameter'] / 2,
+ angle_offset=prm["*first pad angle"],
+ centre=pcbnew.wxPoint(0, 0),
+ clockwise=prm["*number clockwise"])
+
+ array.SetFirstPadInArray(prm["*first pad number"])
+
+ array.AddPadsToModule(self.draw)
+
+ body_radius = (prm['circle diameter'] + prm['pad width'])/2 + self.draw.GetLineTickness()
+ self.draw.Circle(0, 0, body_radius)
+
+ text_size = self.GetTextSize() # IPC nominal
+ thickness = self.GetTextThickness()
+ textposy = body_radius + self.draw.GetLineTickness()/2 + self.GetTextSize()/2 + thickness
+ self.draw.Value( 0, textposy, text_size )
+ self.draw.Reference( 0, -textposy, text_size )
+
+
+
+circular_pad_array_wizard().register()
diff --git a/pcbnew/scripting/plugins/qfp_wizard.py b/pcbnew/scripting/plugins/qfp_wizard.py
new file mode 100644
index 0000000..3cd1eda
--- /dev/null
+++ b/pcbnew/scripting/plugins/qfp_wizard.py
@@ -0,0 +1,125 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+from __future__ import division
+import pcbnew
+
+import HelpfulFootprintWizardPlugin
+import PadArray as PA
+
+
+class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
+
+ def GetName(self):
+ return "QFP"
+
+ def GetDescription(self):
+ return "Quad Flat Package footprint wizard"
+
+ def GenerateParameterList(self):
+ self.AddParam("Pads", "n", self.uNatural, 100)
+ self.AddParam("Pads", "pad pitch", self.uMM, 0.5)
+ self.AddParam("Pads", "pad width", self.uMM, 0.25)
+ self.AddParam("Pads", "pad length", self.uMM, 1.5)
+ self.AddParam("Pads", "vertical pitch", self.uMM, 15)
+ self.AddParam("Pads", "horizontal pitch", self.uMM, 15)
+ self.AddParam("Pads", "oval", self.uBool, True)
+
+ self.AddParam("Package", "package width", self.uMM, 14)
+ self.AddParam("Package", "package height", self.uMM, 14)
+ self.AddParam("Package", "courtyard margin", self.uMM, 1)
+
+ def CheckParameters(self):
+ self.CheckParamInt("Pads", "*n", is_multiple_of=4)
+ self.CheckParamBool("Pads", "*oval")
+
+ def GetValue(self):
+ return "QFP_%d" % self.parameters["Pads"]["*n"]
+
+ def BuildThisFootprint(self):
+ pads = self.parameters["Pads"]
+
+ pad_pitch = pads["pad pitch"]
+ pad_length = self.parameters["Pads"]["pad length"]
+ pad_width = self.parameters["Pads"]["pad width"]
+
+ v_pitch = pads["vertical pitch"]
+ h_pitch = pads["horizontal pitch"]
+
+ pads_per_row = pads["*n"] // 4
+
+ row_len = (pads_per_row - 1) * pad_pitch
+
+ pad_shape = pcbnew.PAD_SHAPE_OVAL if pads["*oval"] else pcbnew.PAD_SHAPE_RECT
+
+ h_pad = PA.PadMaker(self.module).SMDPad( pad_length, pad_width,
+ shape=pad_shape, rot_degree=90.0)
+ v_pad = PA.PadMaker(self.module).SMDPad( pad_length, pad_width, shape=pad_shape)
+
+ #left row
+ pin1Pos = pcbnew.wxPoint(-h_pitch / 2, 0)
+ array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos)
+ array.SetFirstPadInArray(1)
+ array.AddPadsToModule(self.draw)
+
+ #bottom row
+ pin1Pos = pcbnew.wxPoint(0, v_pitch / 2)
+ array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos)
+ array.SetFirstPadInArray(pads_per_row + 1)
+ array.AddPadsToModule(self.draw)
+
+ #right row
+ pin1Pos = pcbnew.wxPoint(h_pitch / 2, 0)
+ array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True,
+ pin1Pos)
+ array.SetFirstPadInArray(2*pads_per_row + 1)
+ array.AddPadsToModule(self.draw)
+
+ #top row
+ pin1Pos = pcbnew.wxPoint(0, -v_pitch / 2)
+ array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False,
+ pin1Pos)
+ array.SetFirstPadInArray(3*pads_per_row + 1)
+ array.AddPadsToModule(self.draw)
+
+ lim_x = self.parameters["Package"]["package width"] / 2
+ lim_y = self.parameters["Package"]["package height"] / 2
+ inner = (row_len / 2) + pad_pitch
+
+ #top left - diagonal
+ self.draw.Line(-lim_x, -inner, -inner, -lim_y)
+ # top right
+ self.draw.Polyline([(inner, -lim_y), (lim_x, -lim_y), (lim_x, -inner)])
+ # bottom left
+ self.draw.Polyline([(-inner, lim_y), (-lim_x, lim_y), (-lim_x, inner)])
+ # bottom right
+ self.draw.Polyline([(inner, lim_y), (lim_x, lim_y), (lim_x, inner)])
+
+ # Courtyard
+ cmargin = self.parameters["Package"]["courtyard margin"]
+ self.draw.SetLayer(pcbnew.F_CrtYd)
+ sizex = (lim_x + cmargin) * 2 + pad_length
+ sizey = (lim_y + cmargin) * 2 + pad_length
+ self.draw.Box(0, 0, sizex, sizey)
+
+ #reference and value
+ text_size = self.GetTextSize() # IPC nominal
+ text_offset = v_pitch / 2 + text_size + pad_length / 2
+
+ self.draw.Value(0, text_offset, text_size)
+ self.draw.Reference(0, -text_offset, text_size)
+
+QFPWizard().register()
diff --git a/pcbnew/scripting/plugins/sdip_wizard.py b/pcbnew/scripting/plugins/sdip_wizard.py
new file mode 100644
index 0000000..31f53cd
--- /dev/null
+++ b/pcbnew/scripting/plugins/sdip_wizard.py
@@ -0,0 +1,237 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+from __future__ import division
+import pcbnew
+
+import HelpfulFootprintWizardPlugin as HFPW
+import PadArray as PA
+
+
+class RowedGridArray(PA.PadGridArray):
+
+ def NamingFunction(self, x, y):
+ pad_cnt = self.nx*self.ny
+
+ if self.ny == 1:
+ return x+1
+
+ if (y % 2) == 0: # upper row, count down
+ return pad_cnt-x
+ else: # lower row, count up
+ return x+1
+
+
+class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
+
+ pad_count_key = 'pas count'
+ row_count_key = 'row count'
+ row_spacing_key = 'row spacing'
+ pad_length_key = 'pad length'
+ pad_width_key = 'pad width'
+ pad_pitch_key = 'pad pitch'
+
+ silkscreen_inside_key = 'silk screen inside'
+ outline_x_margin_key = 'outline x margin'
+ outline_y_margin_key = 'outline y margin'
+
+ def GenerateParameterList(self):
+ # defaults for a DIP package
+ self.AddParam("Pads", self.pad_count_key, self.uNatural, 24)
+ self.AddParam("Pads", self.row_count_key, self.uNatural, 2)
+
+ self.AddParam("Body", self.silkscreen_inside_key, self.uBool, False)
+ self.AddParam("Body", self.outline_x_margin_key, self.uMM, 0.5)
+ self.AddParam("Body", self.outline_y_margin_key, self.uMM, 0.5)
+
+ def CheckParameters(self):
+ self.CheckParamInt("Pads", '*' + self.row_count_key, min_value=1, max_value=2)
+ self.CheckParamInt(
+ "Pads", '*' + self.pad_count_key,
+ is_multiple_of=self.parameters["Pads"]['*' + self.row_count_key])
+
+ # can do this internally to parameter manager?
+ self.CheckParamBool("Body", '*' + self.silkscreen_inside_key)
+
+ def BuildThisFootprint(self):
+ pads = self.parameters["Pads"]
+ body = self.parameters["Body"]
+ num_pads = pads['*' + self.pad_count_key]
+ pad_length = pads[self.pad_length_key]
+ pad_width = pads[self.pad_width_key]
+ row_pitch = pads[self.row_spacing_key]
+ pad_pitch = pads[self.pad_pitch_key]
+ num_rows = pads['*' + self.row_count_key]
+
+ pads_per_row = num_pads // num_rows
+
+ # add in the pads
+ pad = self.GetPad()
+
+ array = RowedGridArray(pad, pads_per_row, num_rows, pad_pitch, row_pitch)
+ array.AddPadsToModule(self.draw)
+
+ # draw the Silk Screen
+ Hsize = pad_pitch * (num_pads / num_rows - 1)
+ Vsize = row_pitch * (num_rows - 1)
+ pin1_posY = -Vsize / 2
+ pin1_posX = -Hsize / 2
+
+ pad_length = pads[self.pad_length_key]
+ pad_width = pads[self.pad_width_key]
+
+ ssx_offset = -pad_width / 2 - body[self.outline_x_margin_key]
+ ssy_offset = -pad_length / 2 - body[self.outline_y_margin_key]
+
+ if body['*' + self.silkscreen_inside_key]:
+ ssy_offset *= -1
+
+ ssx = -pin1_posX - ssx_offset
+ ssy = -pin1_posY - ssy_offset
+
+ self.DrawBox(ssx, ssy)
+
+ #reference and value
+ text_size = self.GetTextSize() # IPC nominal
+
+ if num_rows == 1:
+ text_py = ssy + text_size
+ self.draw.Value(0, -text_py, text_size)
+ self.draw.Reference(0, text_py, text_size)
+ else:
+ text_px = ssx + text_size
+ # self.draw.Value(text_px, 0, text_size, orientation_degree=90)
+ self.draw.Value(0, 0, text_size)
+ self.draw.Reference(-text_px, 0, text_size, orientation_degree=90)
+
+
+class SDIPWizard(RowedFootprint):
+
+ def GetName(self):
+ return "S-DIP"
+
+ def GetDescription(self):
+ return "Single/Dual Inline Package Footprint Wizard"
+
+ def GenerateParameterList(self):
+ RowedFootprint.GenerateParameterList(self)
+
+ self.AddParam("Pads", self.pad_pitch_key, self.uMM, 2.54)
+ self.AddParam("Pads", self.pad_width_key, self.uMM, 1.2)
+ self.AddParam("Pads", self.pad_length_key, self.uMM, 2)
+ self.AddParam("Pads", self.row_spacing_key, self.uMM, 7.52)
+ self.AddParam("Pads", "drill size", self.uMM, 0.8)
+
+ def GetValue(self):
+ pads = self.parameters["Pads"]
+ rows = pads['*' + self.row_count_key]
+ pad_count = pads['*' + self.pad_count_key]
+ row_dist_mil = pcbnew.Iu2Mils(int(self.parameters["Pads"][self.row_spacing_key])) #int(self.parameters["Pads"][self.row_spacing_key] / 2.54 * 100)
+ pad_shape = ""
+
+ if pads[self.pad_width_key] != pads[self.pad_length_key]:
+ pad_shape = '_ELL'
+
+ if rows == 1:
+ name = "SIP"
+ return "%s-%d" % (name, pad_count)
+
+ name = "DIP"
+ return "%s-%d_%d%s" % (name, pad_count, row_dist_mil, pad_shape)
+
+ def GetPad(self):
+ pad_length = self.parameters["Pads"][self.pad_length_key]
+ pad_width = self.parameters["Pads"][self.pad_width_key]
+ drill = self.parameters["Pads"]["drill size"]
+ shape = pcbnew.PAD_SHAPE_CIRCLE
+
+ if pad_length != pad_width:
+ shape = pcbnew.PAD_SHAPE_OVAL
+
+ return PA.PadMaker(self.module).THPad(
+ pad_length, pad_width, drill, shape=shape)
+
+ def DrawBox(self, ssx, ssy):
+
+ if self.parameters["Pads"]['*' + self.row_count_key] == 2:
+
+ # ----------
+ # |8 7 6 5 |
+ # > |
+ # |1 2 3 4 |
+ # ----------
+
+ # draw the notch
+ notchWidth = ssy/1.5
+ notchHeight = self.draw.GetLineTickness()*3
+
+ # NotchedBox draws the notch on top. Rotate the box 90 degrees
+ # to have it on the left
+ self.draw.NotchedBox(0, 0, ssy*2, ssx*2, notchWidth, notchHeight, -90)
+ else:
+ # -----------------
+ # |1|2 3 4 5 6 7 8|
+ # -----------------
+ self.draw.Box(0, 0, ssx*2, ssy*2)
+
+ #line between pin1 and pin2
+ pad_pitch = self.parameters["Pads"][self.pad_pitch_key]
+ pad_cnt = self.parameters["Pads"]['*' + self.pad_count_key]
+ line_x = ( pad_cnt/2 - 1) * pad_pitch
+ self.draw.VLine(-line_x, -ssy, ssy * 2)
+
+ return ssx, ssy
+
+SDIPWizard().register()
+
+
+class SOICWizard(RowedFootprint):
+
+ def GetName(self):
+ return "SOIC"
+
+ def GetDescription(self):
+ return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard"
+
+ def GetValue(self):
+ pad_count = self.parameters["Pads"]['*' + self.pad_count_key]
+ return "%s-%d" % ("SOIC", pad_count)
+
+ def GenerateParameterList(self):
+ RowedFootprint.GenerateParameterList(self)
+
+ #and override some of them
+ self.AddParam("Pads", self.pad_pitch_key, self.uMM, 1.27)
+ self.AddParam("Pads", self.pad_width_key, self.uMM, 0.6)
+ self.AddParam("Pads", self.pad_length_key, self.uMM, 2.2)
+ self.AddParam("Pads", self.row_spacing_key, self.uMM, 5.2)
+
+ def GetPad(self):
+ pad_length = self.parameters["Pads"][self.pad_length_key]
+ pad_width = self.parameters["Pads"][self.pad_width_key]
+ return PA.PadMaker(self.module).SMDPad(
+ pad_length, pad_width, shape=pcbnew.PAD_SHAPE_RECT)
+
+ def DrawBox(self, ssx, ssy):
+
+ # ----------
+ # |8 7 6 5 |
+ # |1 2 3 4 |
+ # \---------
+
+ self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2, pcbnew.FromMM(1))
+
+SOICWizard().register()
diff --git a/pcbnew/scripting/plugins/touch_slider_wizard.py b/pcbnew/scripting/plugins/touch_slider_wizard.py
new file mode 100644
index 0000000..ee2ae53
--- /dev/null
+++ b/pcbnew/scripting/plugins/touch_slider_wizard.py
@@ -0,0 +1,205 @@
+#!/usr/bin/python
+
+#
+# This program source code file is part of KiCad, a free EDA CAD application.
+#
+# Copyright (C) 2012-2014 KiCad Developers, see change_log.txt for contributors.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you may find one here:
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# or you may search the http://www.gnu.org website for the version 2 license,
+# or you may write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+from pcbnew import *
+import HelpfulFootprintWizardPlugin as HFPW
+
+
+class TouchSliderWizard(HFPW.HelpfulFootprintWizardPlugin):
+
+ def GetName(self):
+ """
+ Return footprint name.
+ This is specific to each footprint class, you need to implement this
+ """
+ return 'Touch Slider'
+
+ def GetDescription(self):
+ """
+ Return footprint description.
+ This is specific to each footprint class, you need to implement this
+ """
+ return 'Capacitive Touch Slider wizard'
+
+ def GetValue(self):
+ steps = int(self.parameters["Pads"]["*steps"])
+ return "TS"+str(steps)
+
+ def GenerateParameterList(self):
+ self.AddParam("Pads", "steps", self.uNatural, 4)
+ self.AddParam("Pads", "bands", self.uNatural, 2)
+ self.AddParam("Pads", "width", self.uMM, 10)
+ self.AddParam("Pads", "length", self.uMM, 50)
+ self.AddParam("Pads", "clearance", self.uMM, 1)
+
+ # build a rectangular pad
+ def smdRectPad(self,module,size,pos,name):
+ pad = D_PAD(module)
+ pad.SetSize(size)
+ pad.SetShape(PAD_SHAPE_RECT)
+ pad.SetAttribute(PAD_ATTRIB_SMD)
+ pad.SetLayerSet(pad.ConnSMDMask())
+ pad.SetPos0(pos)
+ pad.SetPosition(pos)
+ pad.SetPadName(name)
+ return pad
+
+
+ def smdTrianglePad(self,module,size,pos,name,up_down=1,left_right=0):
+ pad = D_PAD(module)
+ pad.SetSize(wxSize(size[0],size[1]))
+ pad.SetShape(PAD_SHAPE_TRAPEZOID)
+ pad.SetAttribute(PAD_ATTRIB_SMD)
+ pad.SetLayerSet(pad.ConnSMDMask())
+ pad.SetPos0(pos)
+ pad.SetPosition(pos)
+ pad.SetPadName(name)
+ pad.SetDelta(wxSize(left_right*size[1],up_down*size[0]))
+ return pad
+
+
+ # This method checks the parameters provided to wizard and set errors
+ def CheckParameters(self):
+ prms = self.parameters["Pads"]
+ steps = prms["*steps"]
+ bands = prms["*bands"]
+
+ if steps < 1:
+ self.parameter_errors["Pads"]["*steps"]="steps must be positive"
+ if bands < 1:
+ self.parameter_errors["Pads"]["*bands"]="bands must be positive"
+
+ touch_width = prms["width"]
+ touch_length = prms["length"]
+ touch_clearance = prms["clearance"]
+
+ # The start pad is made of a rectangular pad plus a couple of
+ # triangular pads facing tips on the middle/right of the first
+ # rectangular pad
+ def AddStartPad(self,position,touch_width,step_length,clearance,name):
+ module = self.module
+ step_length = step_length - clearance
+ size_pad = wxSize(step_length/2.0+(step_length/3),touch_width)
+ pad = self.smdRectPad(module,size_pad,position-wxPoint(step_length/6,0),name)
+ module.Add(pad)
+
+ size_pad = wxSize(step_length/2.0,touch_width)
+
+ tp = self.smdTrianglePad(module,wxSize(size_pad[0],size_pad[1]/2),
+ position+wxPoint(size_pad[0]/2,size_pad[1]/4),
+ name)
+ module.Add(tp)
+ tp = self.smdTrianglePad(module,wxSize(size_pad[0],size_pad[1]/2),
+ position+wxPoint(size_pad[0]/2,-size_pad[1]/4),
+ name
+ ,-1)
+ module.Add(tp)
+
+ # compound a "start pad" shape plus a triangle on the left, pointing to
+ # the previous touch-pad
+ def AddMiddlePad(self,position,touch_width,step_length,clearance,name):
+ module = self.module
+ step_length = step_length - clearance
+ size_pad = wxSize(step_length/2.0,touch_width)
+
+ size_pad = wxSize(step_length/2.0,touch_width)
+ pad = self.smdRectPad(module,size_pad,position,name)
+ module.Add(pad)
+
+ tp = self.smdTrianglePad(module,wxSize(size_pad[0],size_pad[1]/2),
+ position+wxPoint(size_pad[0]/2,size_pad[1]/4),
+ name)
+ module.Add(tp)
+ tp = self.smdTrianglePad(module,wxSize(size_pad[0],size_pad[1]/2),
+ position+wxPoint(size_pad[0]/2,-size_pad[1]/4),
+ name
+ ,-1)
+ module.Add(tp)
+
+ tp = self.smdTrianglePad(module,wxSize(size_pad[0],size_pad[1]/2),
+ position+wxPoint(-size_pad[0],0),
+ name,
+ 0,
+ -1)
+ module.Add(tp)
+
+
+ def AddFinalPad(self,position,touch_width,step_length,clearance,name):
+ module = self.module
+ step_length = step_length - clearance
+ size_pad = wxSize(step_length/2.0,touch_width)
+
+ pad = self.smdRectPad(module,
+ wxSize(size_pad[0]+(step_length/3),size_pad[1]),
+ position+wxPoint(step_length/6,0),
+ name)
+ module.Add(pad)
+
+ tp = self.smdTrianglePad(module,wxSize(size_pad[0],size_pad[1]/2),
+ position+wxPoint(-size_pad[0],0),
+ name,
+ 0,
+ -1)
+ module.Add(tp)
+
+ def AddStrip(self,pos,steps,touch_width,step_length,touch_clearance):
+ self.AddStartPad(pos,touch_width,step_length,touch_clearance,"1")
+
+ for n in range(2,steps):
+ pos = pos + wxPoint(step_length,0)
+ self.AddMiddlePad(pos,touch_width,step_length,touch_clearance,str(n))
+
+ pos = pos + wxPoint(step_length,0)
+ self.AddFinalPad(pos,touch_width,step_length,touch_clearance,str(steps))
+
+ # build the footprint from parameters
+ # FIX ME: the X and Y position of the footprint can be better.
+ def BuildThisFootprint(self):
+ prm = self.parameters["Pads"]
+ steps = int(prm["*steps"])
+ bands = int(prm["*bands"])
+ touch_width = prm["width"]
+ touch_length = prm["length"]
+ touch_clearance = prm["clearance"]
+
+ step_length = float(touch_length) / float(steps)
+
+ t_size = self.GetTextSize()
+ w_text = self.draw.GetLineTickness()
+ ypos = touch_width/(bands*2) + t_size/2 + w_text
+ self.draw.Value(0, -ypos, t_size)
+ ypos += t_size + w_text*2
+ self.draw.Reference(0, -ypos, t_size)
+
+ # starting pad
+ pos = wxPointMM(0,0)
+ band_width = touch_width/bands
+
+ for b in range(bands):
+ self.AddStrip(pos,steps,band_width,step_length,touch_clearance)
+ pos += wxPoint(0,band_width)
+
+TouchSliderWizard().register()
+
diff --git a/pcbnew/scripting/plugins/uss39_barcode.py b/pcbnew/scripting/plugins/uss39_barcode.py
new file mode 100644
index 0000000..846a2bc
--- /dev/null
+++ b/pcbnew/scripting/plugins/uss39_barcode.py
@@ -0,0 +1,149 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+from __future__ import division
+import pcbnew as B
+
+import HelpfulFootprintWizardPlugin
+
+'''
+Created on Jan 16, 2015
+
+@author: ejohns
+Rewritten by LordBlick
+'''
+ptd = {
+ '0': '000110100', '1': '100100001', '2': '001100001', '3': '101100000',
+ '4': '000110001', '5': '100110000', '6': '001110000', '7': '000100101',
+ '8': '100100100', '9': '001100100', 'A': '100001001', 'B': '001001001',
+ 'C': '101001000', 'D': '000011001', 'E': '100011000', 'F': '001011000',
+ 'G': '000001101', 'H': '100001100', 'I': '001001100', 'J': '000011100',
+ 'K': '100000011', 'L': '001000011', 'M': '101000010', 'N': '000010011',
+ 'O': '100010010', 'P': '001010010', 'Q': '000000111', 'R': '100000110',
+ 'S': '001000110', 'T': '000010110', 'U': '110000001', 'V': '011000001',
+ 'W': '111000000', 'X': '010010001', 'Y': '110010000', 'Z': '011010000',
+ '-': '010000101', '.': '110000100', ' ': '011000100', '*': '010010100',
+ '$': '010101000', '/': '010100010', '+': '010001010', '%': '000101010'}
+
+class Uss39:
+ def __init__(self, text):
+ self.Text = self.makePrintable(text)
+
+ __str__ = lambda self: self.Text
+ makePrintable = lambda self, text: ''.join((c for c in text.upper() if ptd.has_key(c)))
+
+ def getBarCodePattern(self, text = None):
+ text = text if not(text is None) else self.Text
+ # Reformated text with start and end characters
+ return reduce(lambda a1, a2: a1 + [0] + a2, [map(int, ptd[c]) for c in ("*%s*" % self.makePrintable(text))])
+
+class Uss39Wizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
+ GetName = lambda self: 'BARCODE USS-39'
+ GetDescription = lambda self: 'USS-39 Barcode'
+ GetReferencePrefix = lambda self: 'BARCODE'
+ GetValue = lambda self: self.module.Value().GetText()
+
+ def GenerateParameterList(self):
+ # Silkscreen parameters
+ self.AddParam("Barcode", "Pixel Width", self.uMM, 0.20)
+ self.AddParam("Barcode", "Height", self.uMM, 3.0)
+ self.AddParam("Barcode", "Margin", self.uMM, 2.0)
+ self.AddParam("Barcode", "Contents", self.uString, 'BARCODE')
+ self.AddParam("Caption", "Enabled", self.uBool, True)
+ self.AddParam("Caption", "Height", self.uMM, 1.2)
+ self.AddParam("Caption", "Thickness", self.uMM, 0.12)
+
+ def CheckParameters(self):
+ # Reset constants
+ self.CourtyardLineWidth = B.FromMM(0.05)
+ # Set bar height to the greater of 6.35mm or 0.15*L
+ # Set quiet width to 10*X
+ # User-defined parameters
+ # Create barcode object
+ self.Barcode = Uss39('=' + str(self.parameters['Barcode']['*Contents']))
+ self.X = int(self.parameters['Barcode']['Pixel Width'])
+ self.module.Value().SetText( str(self.Barcode) )
+ self.C = len(str(self.Barcode))
+ # Inter-character gap
+ if self.X < 0.250:
+ self.I = B.FromMM(3.15)
+ else:
+ self.I = (2 * self.X) if (2*self.X) > B.FromMM(1.35) else B.FromMM(1.35)
+ # Wide to narrow ratio
+ if self.X >= B.FromMM(0.508):
+ self.N = B.FromMM(int((2.0+3.0)/2))
+ else:
+ self.N = B.FromMM(int((2.2+3.0)/2))
+ self.H = self.parameters['Barcode']['Height']
+ self.Q = (10 * self.X) if (10 * self.X) > B.FromMM(6.35) else B.FromMM(6.35)
+ self.L = self.I * (1 + self.C) + (self.C + 2) * (6 * self.X + 3 * self.N * self.X) + 2 * self.Q
+
+
+ def __drawBar__(self, bit, x):
+ offset = (bit + 1) * self.X
+ return x + offset
+
+ def __drawSpace__(self, bit, x):
+ self.draw.SetLayer(B.F_SilkS)
+ self.draw.SetLineTickness(self.X)
+ self.draw.Line(x, 0, x, self.H)
+ if (bit == 1):
+ self.draw.Line(x + self.X, 0, x + self.X, self.H)
+ self.draw.Line(x + self.X/2, 0, x + self.X/2, self.H)
+ self.draw.Line(x, 0, x + self.X, 0)
+ self.draw.Line(x, self.H, x + self.X, self.H)
+ offset = (bit + 1) * self.X
+ return x + offset
+
+ def drawBars(self):
+ x = 0
+ bars = self.Barcode.getBarCodePattern()
+ for index in range(0, len(bars), 2):
+ # Draw bar
+ barBit = bars[index]
+ x = self.__drawBar__(barBit, x)
+ # Draw space
+ if index < len(bars)-1:
+ spaceBit = bars[index + 1]
+ x = self.__drawSpace__(spaceBit, x)
+ return x
+
+ def drawQuietZone(self, x0, y0, width, height):
+ self.draw.SetLayer(B.F_SilkS)
+ self.draw.SetLineTickness(self.X)
+
+ for offset in range(0, int(self.Q), int(self.X/2)):
+ xoffset = offset + self.X
+ yoffset = offset + self.X/2
+ self.draw.Line(x0 - xoffset, -yoffset, width + xoffset, -yoffset)
+ self.draw.Line(x0 - xoffset, self.H+yoffset, width + xoffset, self.H+yoffset)
+ self.draw.Line(x0 - xoffset, -yoffset, x0-xoffset, self.H+yoffset)
+ self.draw.Line(width + xoffset, -yoffset, width+xoffset, self.H+yoffset)
+
+ def BuildThisFootprint(self):
+ # Draw bars
+ x = self.drawBars()
+ # Draw quiet zone
+ self.drawQuietZone(0, 0, x, self.H)
+ # Draw courtyard origin
+ self.draw.SetLayer(B.F_CrtYd)
+ self.draw.SetLineTickness(self.CourtyardLineWidth)
+ ch_lim = B.FromMM(0.35)
+ self.draw.Line(-ch_lim, 0, ch_lim, 0)
+ self.draw.Line(0, -ch_lim, 0, ch_lim)
+ self.draw.Circle(0, 0, B.FromMM(0.25))
+ self.module.Value().SetLayer(B.F_Fab)
+
+Uss39Wizard().register()
diff --git a/pcbnew/scripting/plugins/zip_wizard.py b/pcbnew/scripting/plugins/zip_wizard.py
new file mode 100644
index 0000000..4e0f477
--- /dev/null
+++ b/pcbnew/scripting/plugins/zip_wizard.py
@@ -0,0 +1,201 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+from __future__ import division
+import pcbnew
+
+import HelpfulFootprintWizardPlugin as HFPW
+import PadArray as PA
+
+
+class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
+
+ pad_count_key = '#pad count'
+ line_count_key = '#line count'
+ pad_vertical_size_key = 'pad vertical size'
+ pad_horizontal_size_key = 'pad horizontal size'
+ line_spacing_key = 'line spacing'
+ pad_pitch_key = 'pad pitch'
+ drill_size_key = 'drill size'
+
+ courtyard_x_margin_key = 'courtyard x margin'
+ courtyard_y_margin_key = 'courtyard y margin'
+ outline_x_margin_key = 'outline x margin'
+ outline_y_margin_key = 'outline y margin'
+ silkscreen_inside_key = 'silk screen inside'
+
+ def GenerateParameterList(self):
+
+ # defaults for a ZIP package
+ self.AddParam("Pads", self.pad_count_key, self.uNatural, 24)
+ self.AddParam("Pads", self.line_count_key, self.uNatural, 2)
+ self.AddParam("Body", self.silkscreen_inside_key, self.uBool, False)
+ self.AddParam("Body", self.courtyard_x_margin_key, self.uMM, 1)
+ self.AddParam("Body", self.courtyard_y_margin_key, self.uMM, 1)
+
+ def CheckParameters(self):
+ self.CheckParamInt("Pads", '*' + self.pad_count_key)
+ self.CheckParamInt("Pads", '*' + self.line_count_key)
+
+ # can do this internally to parameter manager?
+ self.CheckParamBool("Body", '*' + self.silkscreen_inside_key)
+
+ def BuildThisFootprint(self):
+ pads = self.parameters["Pads"]
+ body = self.parameters["Body"]
+
+ pad_count = pads['*' + self.pad_count_key]
+ pad_Vsize = pads[self.pad_vertical_size_key]
+ pad_Hsize = pads[self.pad_horizontal_size_key]
+ line_pitch = pads[self.line_spacing_key]
+ pad_pitch = pads[self.pad_pitch_key]
+ line_count = pads['*' + self.line_count_key]
+
+ if line_count == 1:
+ singleline = True
+ else:
+ singleline = False
+
+ # add in the pads
+ pad = self.GetPad()
+
+ array = PA.PadZGridArray(pad, pad_count, line_count, line_pitch, pad_pitch)
+ array.AddPadsToModule(self.draw)
+
+ # draw the Silk Screen
+ pads_per_line = pad_count // line_count
+ row_length = pad_pitch * (pads_per_line - 1) # fenceposts
+ ssx_offset = pad_Hsize / 2 + body[self.outline_x_margin_key]
+ ssy_offset = pad_Vsize / 2 + body[self.outline_y_margin_key]
+
+ pin1posX = pad_pitch * (pad_count - 1) / 2
+ pin1posY = line_pitch * (line_count - 1) / 2
+ leftx = pin1posX + ssx_offset
+ lowy = pin1posY + ssy_offset
+
+ cornery = lowy
+
+ # body inside pads is possible only for 2 rows.
+ # for other values, there is no room
+ linew = self.draw.GetLineTickness()
+ if body['*'+self.silkscreen_inside_key] and line_count == 2:
+ cornery = pin1posY - ssy_offset
+ if cornery < linew:
+ cornery = linew
+
+ self.DrawBox(leftx*2, cornery*2)
+
+ # Courtyard
+ cmarginx = body[self.courtyard_x_margin_key]
+ cmarginy = body[self.courtyard_y_margin_key]
+ self.draw.SetLayer(pcbnew.F_CrtYd)
+ sizex = (pin1posX + cmarginx) * 2 + pad_Hsize
+ sizey = (pin1posY + cmarginy) * 2 + pad_Vsize
+ self.draw.Box(0, 0, sizex, sizey)
+
+ #reference and value
+ text_size = self.GetTextSize() # IPC nominal
+ t_posy = lowy + text_size
+
+ self.draw.Value(0, t_posy, text_size)
+ self.draw.Reference(0, -t_posy, text_size)
+
+ def DrawBox(self, sizex, sizey):
+
+ # ----------
+ # | 2 4 6 8|
+ # |1 3 5 7 |
+ # \---------
+ setback = pcbnew.FromMM(1)
+
+ if setback > sizey/2:
+ setback = sizey/2
+
+ self.draw.BoxWithDiagonalAtCorner(0, 0, sizex, sizey, setback, self.draw.flipY)
+
+
+class ZIPWizard(RowedFootprint):
+
+ def GetName(self):
+ return "ZIP"
+
+ def GetDescription(self):
+ return "N lines Zip Package Footprint Wizard"
+
+ def GenerateParameterList(self):
+ RowedFootprint.GenerateParameterList(self)
+
+ self.AddParam("Pads", self.pad_pitch_key, self.uMM, 1.27)
+ self.AddParam("Pads", self.pad_horizontal_size_key, self.uMM, 1.2)
+ self.AddParam("Pads", self.pad_vertical_size_key, self.uMM, 2)
+ self.AddParam("Pads", self.line_spacing_key, self.uMM, 2.54)
+ self.AddParam("Pads", self.drill_size_key, self.uMM, 0.8)
+ self.AddParam("Body", self.outline_x_margin_key, self.uMM, 1)
+ self.AddParam("Body", self.outline_y_margin_key, self.uMM, 0.5)
+
+ def GetValue(self):
+ rows = self.parameters["Pads"]['*' + self.line_count_key]
+ pad_cnt = self.parameters["Pads"]['*' + self.pad_count_key]
+
+ if rows == 1:
+ name = "SIP"
+ elif rows == 2:
+ name = "ZIP"
+ else: # triple and up aren't really a thing, but call it something!
+ name = "xIP"
+
+ return "%s-%d" % (name, pad_cnt)
+
+ def GetPad(self):
+ pad_Vsize = self.parameters["Pads"][self.pad_vertical_size_key]
+ pad_Hsize = self.parameters["Pads"][self.pad_horizontal_size_key]
+ drill = self.parameters["Pads"][self.drill_size_key]
+ return PA.PadMaker(self.module).THPad(
+ pad_Vsize, pad_Hsize, drill, shape=pcbnew.PAD_SHAPE_OVAL)
+
+ZIPWizard().register()
+
+
+class ZOICWizard(RowedFootprint):
+
+ def GetName(self):
+ return "ZOIC"
+
+ def GetDescription(self):
+ return "ZOIC, etc, Footprint Wizard"
+
+ def GetValue(self):
+ return "%s-%d" % ("ZOIC", self.parameters["Pads"]['*' + self.pad_count_key])
+
+ def GenerateParameterList(self):
+ RowedFootprint.GenerateParameterList(self)
+
+ #and override some of them
+ self.AddParam("Pads", self.pad_pitch_key, self.uMM, 0.6)
+ self.AddParam("Pads", self.pad_horizontal_size_key, self.uMM, 0.6)
+ self.AddParam("Pads", self.pad_vertical_size_key, self.uMM, 1.8)
+ self.AddParam("Pads", self.line_spacing_key, self.uMM, 5.2)
+
+ self.AddParam("Body", self.outline_x_margin_key, self.uMM, 0.5)
+ self.AddParam("Body", self.outline_y_margin_key, self.uMM, 1)
+
+ def GetPad(self):
+ pad_Vsize = self.parameters["Pads"][self.pad_vertical_size_key]
+ pad_Hsize = self.parameters["Pads"][self.pad_horizontal_size_key]
+ return PA.PadMaker(self.module).SMDPad(
+ pad_Vsize, pad_Hsize, shape=pcbnew.PAD_SHAPE_RECT)
+
+ZOICWizard().register()
diff --git a/pcbnew/scripting/python_console_frame.h b/pcbnew/scripting/python_console_frame.h
new file mode 100644
index 0000000..042e6b0
--- /dev/null
+++ b/pcbnew/scripting/python_console_frame.h
@@ -0,0 +1,105 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
+ * Copyright (C) 2004-2014 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file python_console_frame.h
+ */
+
+#ifndef PYTHON_CONSOLE_FRAME_H_
+#define PYTHON_CONSOLE_FRAME_H_
+
+#if defined(KICAD_SCRIPTING) || defined(KICAD_SCRIPTING_WXPYTHON)
+#include <python_scripting.h>
+#endif
+
+
+/**
+ * Class PYTHON_CONSOLE_FRAME is a simple derived class from wxMiniFrame
+ * to handle the scripting python console
+ */
+#define PC_STYLE wxCAPTION|wxCLOSE_BOX|wxRESIZE_BORDER
+
+class PYTHON_CONSOLE_FRAME : public wxMiniFrame
+{
+private:
+ static wxSize m_frameSize; ///< The size of the frame, stored during a session
+ static wxPoint m_framePos; ///< The position of the frame, stored during a session
+ wxWindow * m_pythonPanel; ///< the window managed by the python shell
+
+public:
+
+ PYTHON_CONSOLE_FRAME( wxWindow* aParent, const wxString& aFramenameId )
+ : wxMiniFrame( aParent, wxID_ANY, wxT("Python console"), wxDefaultPosition, wxDefaultSize,
+ PC_STYLE | wxFRAME_FLOAT_ON_PARENT, aFramenameId )
+ {
+ wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
+ SetSizer( sizer );
+ SetMinSize( wxSize( 500, 200 ) );
+
+#if defined(KICAD_SCRIPTING_WXPYTHON)
+ m_pythonPanel = CreatePythonShellWindow( this );
+ sizer->Add( m_pythonPanel, 1, wxEXPAND, 0 );
+#else
+ m_pythonPanel = NULL;
+#endif
+
+ if( m_frameSize.x <= 0 || m_frameSize.y <= 0 )
+ SetSize( wxSize( 600, 300 ) );
+ else
+ SetSize( m_frameSize );
+
+ if( m_framePos.x == 0 && m_framePos.y == 0 )
+ Centre();
+ else
+ SetPosition( m_framePos );
+
+ Layout();
+
+ // Connect Events
+ this->Connect( wxEVT_CLOSE_WINDOW,
+ wxCloseEventHandler( PYTHON_CONSOLE_FRAME::OnClose ) );
+ }
+
+ ~PYTHON_CONSOLE_FRAME()
+ {
+ // Disconnect Events
+ this->Disconnect( wxEVT_CLOSE_WINDOW,
+ wxCloseEventHandler( PYTHON_CONSOLE_FRAME::OnClose ) );
+ }
+
+private:
+
+ void OnClose( wxCloseEvent& event )
+ {
+ if( !IsIconized() )
+ {
+ m_frameSize = GetSize();
+ m_framePos = GetPosition();
+ }
+
+ event.Skip();
+ }
+};
+
+#endif // PYTHON_CONSOLE_FRAME_H_
diff --git a/pcbnew/scripting/tests/test1.py b/pcbnew/scripting/tests/test1.py
new file mode 100644
index 0000000..b1f7cff
--- /dev/null
+++ b/pcbnew/scripting/tests/test1.py
@@ -0,0 +1,11 @@
+import pcbnew
+
+pcb = pcbnew.GetBoard()
+
+for m in pcb.GetModules():
+ print m.GetPosition()
+ for p in m.Pads():
+ print "p=>",p.GetPosition(),p.GetPadName()
+ print p.GetPosition()
+
+
diff --git a/pcbnew/scripting/tests/test2.py b/pcbnew/scripting/tests/test2.py
new file mode 100644
index 0000000..e925f88
--- /dev/null
+++ b/pcbnew/scripting/tests/test2.py
@@ -0,0 +1,8 @@
+import pcbnew
+
+pcb = pcbnew.GetBoard()
+
+for m in pcb.GetModules():
+ print m.GetReference(),"(",m.GetValue(),") at ", m.GetPosition()
+ for p in m.Pads():
+ print " pad",p.GetPadName(), "at",p.GetPosition()
diff --git a/pcbnew/scripting/units.i b/pcbnew/scripting/units.i
new file mode 100644
index 0000000..56ea213
--- /dev/null
+++ b/pcbnew/scripting/units.i
@@ -0,0 +1,78 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
+ * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * @file units.i
+ * @brief unit conversion code
+ */
+
+// Unit conversion, between internal units and mm or mils
+
+%pythoncode
+{
+ def ToMM(iu):
+ if type(iu) in [int,float]:
+ return float(iu) / float(IU_PER_MM)
+ elif type(iu) in [wxPoint,wxSize]:
+ return tuple(map(ToMM,iu))
+
+ def FromMM(mm):
+ if type(mm) in [int,float]:
+ return int(float(mm) * float(IU_PER_MM))
+ elif type(mm) in [wxPoint,wxSize]:
+ return tuple(map(FromMM,mm))
+
+ def ToMils(iu):
+ if type(iu) in [int,float]:
+ return float(iu) / float(IU_PER_MILS)
+ elif type(iu) in [wxPoint,wxSize]:
+ return tuple(map(ToMils,iu))
+
+ def FromMils(mils):
+ if type(mils) in [int,float]:
+ return int(float(mils)*float(IU_PER_MILS))
+ elif type(mils) in [wxPoint,wxSize]:
+ return tuple(map(FromMils,mils))
+
+ def wxSizeMM(mmx,mmy): return wxSize(FromMM(mmx),FromMM(mmy))
+ def wxSizeMils(mmx,mmy): return wxSize(FromMils(mmx),FromMils(mmy))
+
+ def wxPointMM(mmx,mmy): return wxPoint(FromMM(mmx),FromMM(mmy))
+ def wxPointMils(mmx,mmy): return wxPoint(FromMils(mmx),FromMils(mmy))
+
+ def wxRectMM(x,y,wx,wy):
+ x = int(FromMM(x))
+ y = int(FromMM(y))
+ wx = int(FromMM(wx))
+ wy = int (FromMM(wy))
+ return wxRect(x,y,wx,wy)
+
+ def wxRectMils(x,y,wx,wy):
+ x = int(FromMils(x))
+ y = int(FromMils(y))
+ wx = int(FromMils(wx))
+ wy = int (FromMils(wy))
+ return wxRect(x,y,wx,wy)
+
+}