This chapter is about programming extensions for KLayout using the integrated Ruby API (RBA) or Python API (pya).
To use RBA scripts, KLayout must be compiled with the Ruby interpreter. Check under "Help/About" whether support is available. If there is, the "Build options" will include a "Ruby" or "Python" interpreter or both. RBA scripts require a Ruby interpreter. To use pya scripts, Python support must be included.
KLayout comes with the Qt library included into the Ruby or Python API. This means, KLayout scripts can access the full Qt API if Qt binding is available. Check whether "Qt bindings for scripts" is included in the build options on the "Help/About" page.
Basically there are scripts and macros:
Before you start, please make yourself familiar with the macro development integrated environment (). This documentation also assumes that you familiar with the Ruby programming language. There are numerous books and tutorials about Ruby. The most famous one is the "pickaxe book" (Programming Ruby - The Pragmatic Programmers Guide) by Dave Thomas. If you are familiar with Ruby there is a technical article about the way Ruby and KLayout's core are integrated (). There are special articles about the integrated Qt binding () and PCell programming (). If you want to use Python, please read the python implementation article () for details about how to translate Ruby samples into Python and specific details of the Python integration.
An introduction into the basic concepts of the KLayout API are given in the article about the application API () and about the database API ().
The first sample is already a complete macro which counts all selected paths, boxes, polygons or text objects. It demonstrates how to set up a macro, how to deal with the selection and how to access the layout database.
Here is the code:
module MyMacro
include RBA
app = Application.instance
mw = app.main_window
lv = mw.current_view
if lv == nil
raise "Shape Statistics: No view selected"
end
paths = 0
polygons = 0
boxes = 0
texts = 0
lv.each_object_selected do |sel|
shape = sel.shape
if shape.is_path?
paths += 1
elsif shape.is_box?
boxes += 1
elsif shape.is_polygon?
polygons += 1
elsif shape.is_text?
texts += 1
end
end
s = "Paths: #{paths}\n"
s += "Polygons: #{polygons}\n"
s += "Boxes: #{boxes}\n"
s += "Texts: #{texts}\n"
MessageBox::info("Shape Statistics", s, MessageBox::Ok)
end
To run the macro, create a new macro in the macro development IDE: choose "Macros/Macro Development". Create a new macro using the "+" button. Rename the macro to a suitable name. Copy the code above into the text. Load a layout, select some objects and in the macro development IDE press F5. A message box will appear the tells us how may boxes, polygons etc. we have selected.
If we look at the code, the first observation is that we put the whole script into our own namespace (we can use any name which is not used otherwise). The advantage of that approach is that we can import the "RBA" namespace which makes life somewhat easier. The RBA namespace contains all KLayout classes and constants. If we would import the RBA namespace into the main namespace we would do that for all other scripts in KLayout since the main namespace is a common resource for all scripts.
The first thing we do inside the macro is to access the layout view:
app = Application.instance
mw = app.main_window
lv = mw.current_view
if lv == nil
raise "Shape Statistics: No view selected"
end
The Application class (
The next object which is important is the MainWindow object (
The layout view is the representation of a layout tab (
A main window can display multiple tabs. Hence there are multiple LayoutView objects available. The currently selected tab can be addressed with the "current_view" method. This method delivers the LayoutView object associated with that tab. If no layout is loaded, that method returns nil (the Ruby for "nothing")
Actually the preparation step can be simplified without needing the Application and MainWindow object. For demonstration purposes it was included however. Here is the short version:
lv = LayoutView.current || raise "Shape Statistics: No view selected"
The actual layouts loaded are entities separated from the views. Technically, there is a many-to-many relationship between layout views and layout objects. A layout view may display multiple layouts and one layout may be displayed in multiple layout views. In addition, a layout view can address different cells from a layout. A layout view has a current cell and a path that leads to that cell. The path consists of a specific and unspecific part. The unspecific part of the path tells where the cell we show as the current cell is located in the cell tree. The unspecific part is a tribute to the fact that a cell can appear in different branches of the cell tree (i.e. as child of cell A and cell B). The specific part of the path addresses a specific instance of within some cell (the "context cell") above in the hierarchy. A specific path is created when we descend down in the hierarchy along a certain instantiation path.
Layout, current cell, context cell, specific and unspecific
path are combined into the CellView object (
For our sample we don't need the CellView objects, because we get all information directly from the view. But the concept of that object is important to understand the API documentation. Here we ask the layout view for all selected objects and collect the object counts:
lv.each_object_selected do |sel|
shape = sel.shape
if shape.is_path?
paths += 1
elsif shape.is_box?
boxes += 1
elsif shape.is_polygon?
polygons += 1
elsif shape.is_text?
texts += 1
end
end
"each_object_selected" is a method of the LayoutView object. More precisely it's an iterator which calls the
given block for each selected object. Since the layout view can show multiple layouts, the selected objects may
originate from different layouts. In addition, the object may be selected in a child cell of the current cell.
Hence, the selection is described by a cell view index (indicating which layout it resided in), an instantiation path (a sequence of instances leading to
the cell containing the selected object from the current cell) and the actual object selected.
That information is combined into an ObjectInstPath object (
In our case we are not interested in the cell view that shape lives in. Neither are we in the instantiation path.
Hence all we need is the shape and we can obtain it with the "shape" method.
This method delivers a Shape object (
Finally we put together a message and display it in a message box:
s = "Paths: #{paths}\n"
s += "Polygons: #{polygons}\n"
s += "Boxes: #{boxes}\n"
s += "Texts: #{texts}\n"
MessageBox::info("Shape Statistics", s, MessageBox::Ok)
MessageBox (
This is just a simple example, but it already illustrates some basic concepts. For a in-depth introduction into the API, read and .