mirror of https://github.com/KLayout/klayout.git
259 lines
9.2 KiB
XML
259 lines
9.2 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
|
|
|
|
<doc>
|
|
|
|
<title>Traditional Ruby Programming</title>
|
|
<keyword name="Programming"/>
|
|
<keyword name="RBA"/>
|
|
<keyword name="Ruby scripts"/>
|
|
|
|
<index/>
|
|
|
|
<p>
|
|
Before version 0.21 and the development IDE, Ruby scripts had to be prepared externally and KLayout had to be
|
|
restarted to use them. In addition, binding a script to a menu entry required some coding.
|
|
This method still is supported for version 0.22, hence it is described here. It is provided for backward compatibility
|
|
and because KLayout can be used as a standalone engine for RBA scripts without a user interface.
|
|
</p>
|
|
|
|
<h2>Using RBA scripts</h2>
|
|
|
|
<p>
|
|
To use RBA, the script location must be passed to KLayout using the "-r" option (in this example "hello_world.rb"):
|
|
</p>
|
|
|
|
<pre>
|
|
klayout -r hello_world.rb</pre>
|
|
|
|
<p>
|
|
If used this way, all RBA functionality must be put into one script. Usually, this script will provide all the
|
|
classes and definitions required and register new menu items and handlers.
|
|
</p>
|
|
|
|
<h2>Basic RBA</h2>
|
|
|
|
<p>
|
|
The ruby script given with the "-r" option is executed before the actual application is
|
|
started. In fact, the application execution is initiated by the script, if one is given.
|
|
In order to make the application start, the ruby script must contain at least this statement:
|
|
</p>
|
|
|
|
<pre>
|
|
RBA::Application.instance.exec</pre>
|
|
|
|
<p>
|
|
"RBA" is the module provided by KLayout. "Application" is the main controller class (a singleton)
|
|
that refers to the application as a whole. It provides the "exec" method which runs the application
|
|
and returns if the main window is closed.
|
|
</p>
|
|
|
|
<p>
|
|
In most cases, the script will perform initialization steps before calling "exec" and may do cleanup
|
|
once the application returned. Initialization may involve loading of layouts, registering menu items,
|
|
initializing other resources etc. However, the "exec" call can be omitted and then KLayout acts as
|
|
a pure interpreter for the script.
|
|
</p>
|
|
|
|
<p>
|
|
In larger applications
|
|
however, source code is usually organised into libraries and a main code part. Libraries and
|
|
supplementary code can be loaded prior to the loading of the main source with the "-rm" option. Files loaded
|
|
with this option do not need to (and in fact must not) contain the "RBA::Application.instance.exec" call. This allows
|
|
providing independent libraries and initialisation code to a RBA script environment:
|
|
</p>
|
|
|
|
<pre>
|
|
klayout -rm setup1.rb -rm setup2.rb -r hello_world.rb</pre>
|
|
|
|
<p>
|
|
RBA code can be installed globally by creating a file with suffix ".rbm" in the same directory than the
|
|
KLayout binary. If such files are encountered, they will be executed automatically
|
|
before all files specified with "-rm" and "-r" are read.
|
|
</p>
|
|
|
|
<h2>A simple example</h2>
|
|
|
|
<p>
|
|
This example script registers a new menu item in the toolbar, which displays a message box saying "Hello, world!"
|
|
when selected, and runs the application:
|
|
</p>
|
|
|
|
<pre>
|
|
class MenuHandler < RBA::Action
|
|
def triggered
|
|
RBA::MessageBox::info( "Info", "Hello, world!", RBA::MessageBox::b_ok )
|
|
end
|
|
end
|
|
|
|
app = RBA::Application.instance
|
|
|
|
$menu_handler = MenuHandler.new
|
|
$menu_handler.title = "RBA test"
|
|
|
|
menu = app.main_window.menu
|
|
menu.insert_item("@toolbar.end", "rba_test", $menu_handler)
|
|
menu.insert_item("tools_menu.end", "rba_test", $menu_handler)
|
|
|
|
app.exec</pre>
|
|
|
|
<p>
|
|
This simple example already demonstrates some important concepts:
|
|
</p>
|
|
|
|
<ul>
|
|
<li><b>Reimplementation</b>: the menu item's functionality is implemented by
|
|
reimplementing the Action object's "triggered" method. This method is called
|
|
when the menu item is selected.</li>
|
|
<li><b>Delegation</b>: the menu item is not implemented directly but
|
|
the implementation is delegated to an "Action" object. The action provides
|
|
the "slot" that the menu item refers to. One action may be used for multiple
|
|
menu items. The action does not only provide the implementation but the
|
|
title, keyboard shortcut and other properties of the menu item. This way, the
|
|
action may be used in multiple places (i.e. menu and toolbar) and still appear
|
|
the same.</li>
|
|
<li><b>Menu item addressing</b>: The menu item is addressed by a "path" expression.
|
|
In this case, the path is used for specifying the place where to insert the item.
|
|
The path "@toolbar.end" instructs the menu controller to insert the item at the
|
|
end of the toolbar. The path "tools_menu.end" instructs it to insert the item at
|
|
the end of the "Tools" menu. The second string passed to "insert" is the name
|
|
of the new item. After inserting, the new item can be addressed with the path "@toolbar.rba_test"
|
|
and "tools_menu.rba_test".</li>
|
|
<li><b>Ownership of objects</b>: RBA is not able to guarantee a certain lifetime of an
|
|
object, because Ruby and C++ implement different lifetime management models. Specifically, for
|
|
the action object this means, that the menu controller, which is implemented in C++ cannot
|
|
tell ruby that it keeps a reference to the action object. Without further measures, ruby will
|
|
ignore this relationship and delete the action object - the menu item will disappear.
|
|
To overcome this problem, an explicit reference to the action object must be held. In this
|
|
case, a global variable is used ("$menu_handler"). This could as well be a member of an object
|
|
or an array member.<br/>
|
|
It is very important to keep this aspect in mind when designing RBA applications.
|
|
</li>
|
|
</ul>
|
|
|
|
<p>
|
|
Documentation for the various classes involved can be found in <link href="/code/index.xml"/>.
|
|
</p>
|
|
|
|
<h2>Extending the example</h2>
|
|
|
|
<p>
|
|
To give the menu callback a more "ruby style" look, a wrapper can be created what allows
|
|
to attach code to the menu in the style of a ruby iterator. Now the callback uses "yield" to
|
|
execute the code attached to the menu. In addition, the menu item now uses a icon and a keyboard
|
|
shortcut ("Shift+F7"):
|
|
</p>
|
|
|
|
<pre>
|
|
class MenuHandler < RBA::Action
|
|
def initialize( t, k, i, &action )
|
|
self.title = t
|
|
self.shortcut = k
|
|
self.icon = i
|
|
@action = action
|
|
end
|
|
def triggered
|
|
@action.call( self )
|
|
end
|
|
private
|
|
@action
|
|
end
|
|
|
|
app = RBA::Application.instance
|
|
|
|
$menu_handler = MenuHandler.new( "RBA test", "Shift+F7", "icon.png" ) {
|
|
RBA::MessageBox::info( "Info", "Hello, world!", RBA::MessageBox::b_ok )
|
|
}
|
|
|
|
menu = app.main_window.menu
|
|
menu.insert_item("@toolbar.end", "rba_test", $menu_handler)
|
|
menu.insert_item("tools_menu.end", "rba_test", $menu_handler)
|
|
|
|
app.exec</pre>
|
|
|
|
<h2>Events</h2>
|
|
|
|
<p>
|
|
Starting with version 0.21, RBA features "events". Events allow to specify a Ruby block which
|
|
is called when a certain condition takes place. Using events eliminates the need for
|
|
deriving a from an existing class. In particular, with version 0.21, RBA::Action features one
|
|
event called "on_triggered". A block associated with this event is called, when the action
|
|
is triggered.
|
|
</p>
|
|
|
|
<p>
|
|
With events the example looks like that:
|
|
</p>
|
|
|
|
<pre>
|
|
app = RBA::Application.instance
|
|
|
|
$menu_handler = RBA::Action.new
|
|
$menu_handler.title = "RBA test"
|
|
$menu_handler.shortcut = "Shift+F7"
|
|
$menu_handler.icon = "icon.png"
|
|
|
|
# install the event
|
|
$menu_handler.on_triggered {
|
|
RBA::MessageBox::info( "Info", "Hello, world!", RBA::MessageBox::b_ok )
|
|
}
|
|
|
|
menu = app.main_window.menu
|
|
menu.insert_item("@toolbar.end", "rba_test", $menu_handler)
|
|
menu.insert_item("tools_menu.end", "rba_test", $menu_handler)
|
|
|
|
app.exec</pre>
|
|
|
|
<h2>Using KLayout as a pure interpreter</h2>
|
|
|
|
<p>
|
|
KLayout can be used as a RBA interpreter without user interface. That allows implementation of
|
|
layout processing scripts using the provided RBA bindings to the layout database objects, namely RBA::Layout.
|
|
You cannot use user interface objects
|
|
in that mode and the RBA::MainWindow instance will be nil. You can pass parameters from the command line to
|
|
the script by defining Ruby variables.
|
|
</p>
|
|
|
|
<p>
|
|
Here is an example which reads a layout and converts it to OASIS with some special settings:
|
|
</p>
|
|
|
|
<pre>
|
|
ly = RBA::Layout.new
|
|
ly.read($input)
|
|
|
|
gzip = false # or true to use gzip on the file
|
|
|
|
# special settings for OASIS output
|
|
opt = RBA::SaveLayoutOptions::new
|
|
opt.format = "OASIS"
|
|
opt.dbu = 0.0001
|
|
opt.oasis_write_cblocks = true
|
|
opt.oasis_strict_mode = false
|
|
opt.oasis_compression_level = 10
|
|
|
|
ly.write($output, gzip, opt)</pre>
|
|
|
|
<p>
|
|
Assume that script is saved to "write_oas.rb". To run that script, use the following KLayout call:
|
|
</p>
|
|
|
|
<pre>
|
|
klayout -rx -r write_oas.rb -z -rd input=in.gds -rd output=out.oas</pre>
|
|
|
|
<p>
|
|
The two "-rd" options will instruct KLayout to define two Ruby variables for the input and output file name. They can be used
|
|
as "$input" and "$output" in the script.
|
|
</p>
|
|
<p>"-z" will disable the user interface. Therefore, this
|
|
KLayout call can be used in scripts and on servers without X connection for example.
|
|
</p>
|
|
<p>"-rx" will
|
|
disable all implicitly loaded scripts such as autorun macros which speeds up application start and
|
|
avoids undesired side effects.
|
|
</p>
|
|
|
|
</doc>
|
|
|
|
|