mirror of https://github.com/KLayout/klayout.git
Rewriting Python samples to klayout.* modules, fixing some bugs and flaws in the samples
This commit is contained in:
parent
22042a0b10
commit
d35e21be29
|
|
@ -8,10 +8,6 @@
|
||||||
<doc>@class [db] PCellDeclarationHelper < PCellDeclaration
|
<doc>@class [db] PCellDeclarationHelper < PCellDeclaration
|
||||||
@brief A helper class to simplify the declaration of a PCell (Python version)
|
@brief A helper class to simplify the declaration of a PCell (Python version)
|
||||||
|
|
||||||
NOTE: in the following, "pya" can be replaced by "klayout.db" which is
|
|
||||||
the canonical module and the preferred way of addressing the
|
|
||||||
external Python library.
|
|
||||||
|
|
||||||
This class provides adds some convenience to the PCell declaration based
|
This class provides adds some convenience to the PCell declaration based
|
||||||
on PCellDeclaration. PCellDeclaration is a C++ object which is less
|
on PCellDeclaration. PCellDeclaration is a C++ object which is less
|
||||||
convenient to use than a Ruby-based approach. In particular this class
|
convenient to use than a Ruby-based approach. In particular this class
|
||||||
|
|
@ -22,10 +18,10 @@ The basic usage of this class is the following:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
|
|
||||||
import pya
|
import klayout.db as kdb
|
||||||
|
|
||||||
# Derive your PCell from PCellDeclarationHelper
|
# Derive your PCell from PCellDeclarationHelper
|
||||||
class MyPCell(pya.PCellDeclarationHelper):
|
class MyPCell(kdb.PCellDeclarationHelper):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
|
@ -35,7 +31,7 @@ class MyPCell(pya.PCellDeclarationHelper):
|
||||||
# your initialization: add parameters with name, type, description and
|
# your initialization: add parameters with name, type, description and
|
||||||
# optional other values
|
# optional other values
|
||||||
self.param("p", self.TypeInt, "The parameter", default = 1)
|
self.param("p", self.TypeInt, "The parameter", default = 1)
|
||||||
self.param("l", self.TypeLayer, "The layer", default = pya.LayerInfo(1, 0))
|
self.param("l", self.TypeLayer, "The layer", default = kdb.LayerInfo(1, 0))
|
||||||
# add other parameters ..
|
# add other parameters ..
|
||||||
|
|
||||||
# reimplement display_text_impl
|
# reimplement display_text_impl
|
||||||
|
|
@ -71,7 +67,7 @@ we can access the layer index with the "l_layer" method:
|
||||||
|
|
||||||
@code
|
@code
|
||||||
def produce_impl(self):
|
def produce_impl(self):
|
||||||
cell.shapes(self.l_layer).insert(pya.Box(0, 0, self.p*100, self.p*200))
|
cell.shapes(self.l_layer).insert(kdb.Box(0, 0, self.p*100, self.p*200))
|
||||||
@/code
|
@/code
|
||||||
|
|
||||||
Again in this sample, we used "p" to access the parameter "p".
|
Again in this sample, we used "p" to access the parameter "p".
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,7 @@ end
|
||||||
|
|
||||||
The Python version is this:
|
The Python version is this:
|
||||||
|
|
||||||
<pre>
|
<pre>from klayout.lay import BrowserSource, BrowserDialog
|
||||||
from pya import BrowserSource, BrowserDialog
|
|
||||||
|
|
||||||
class MyBrowserSource(BrowserSource):
|
class MyBrowserSource(BrowserSource):
|
||||||
def get(self, url):
|
def get(self, url):
|
||||||
|
|
@ -157,8 +156,7 @@ end
|
||||||
The Python version is:
|
The Python version is:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>from klayout.lay import Action, MessageBox, Application
|
||||||
from pya import Action, MessageBox, Application
|
|
||||||
|
|
||||||
def on_triggered():
|
def on_triggered():
|
||||||
MessageBox.info("A message", "The action was triggered", MessageBox.Ok)
|
MessageBox.info("A message", "The action was triggered", MessageBox.Ok)
|
||||||
|
|
@ -235,8 +233,8 @@ end
|
||||||
The Python version is:
|
The Python version is:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>from klayout.lay import Application
|
||||||
from pya import QDialog, QVBoxLayout, QLineEdit, QLabel, Application
|
from klayout.QtWidgets import QDialog, QVBoxLayout, QLineEdit, QLabel
|
||||||
|
|
||||||
dialog = QDialog(Application.instance().main_window())
|
dialog = QDialog(Application.instance().main_window())
|
||||||
layout = QVBoxLayout(dialog)
|
layout = QVBoxLayout(dialog)
|
||||||
|
|
@ -285,8 +283,8 @@ end
|
||||||
with the Python version:
|
with the Python version:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>from klayout.lay import Application
|
||||||
from pya import QDialog, QVBoxLayout, QLineEdit, QLabel, Application
|
from klayout.QtWidgets import QDialog, QVBoxLayout, QLineEdit, QLabel
|
||||||
|
|
||||||
dialog = QDialog(Application.instance().main_window())
|
dialog = QDialog(Application.instance().main_window())
|
||||||
layout = QVBoxLayout(dialog)
|
layout = QVBoxLayout(dialog)
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,17 @@
|
||||||
<keyword name="Ruby scripts"/>
|
<keyword name="Ruby scripts"/>
|
||||||
<keyword name="Python"/>
|
<keyword name="Python"/>
|
||||||
<keyword name="pya"/>
|
<keyword name="pya"/>
|
||||||
|
<keyword name="Python module"/>
|
||||||
<keyword name="Python scripts"/>
|
<keyword name="Python scripts"/>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This chapter is about programming extensions for KLayout using the integrated Ruby API (RBA) or Python API (pya).
|
This chapter is about programming extensions for KLayout using the integrated Ruby API (RBA) or Python API (klayout.db, klayout.layer etc.).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
To use RBA scripts, KLayout must be compiled with the Ruby interpreter. Check under "Help/About" whether
|
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.
|
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.
|
RBA scripts require a Ruby interpreter. To use Python scripts, Python support must be compiled in.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
<keyword name="Programming"/>
|
<keyword name="Programming"/>
|
||||||
<keyword name="Python"/>
|
<keyword name="Python"/>
|
||||||
<keyword name="pya"/>
|
<keyword name="pya"/>
|
||||||
|
<keyword name="Python module"/>
|
||||||
<keyword name="Python scripts"/>
|
<keyword name="Python scripts"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -55,8 +56,11 @@
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Apart from a few specialities and the different language of course, Python macros do not look much different from Ruby
|
Apart from a few specialities and the different language of course, Python macros do not look much different from Ruby
|
||||||
macros. Ruby's "RBA" namespace is "pya" for Python (lowercase to conform with PEP-8). The
|
macros. Ruby's "RBA" namespace is "klayout" for Python (lowercase to conform with PEP-8).
|
||||||
class and methods names are the same with very few exceptions and the documentation can be
|
The "klayout" module has a number of submodules like "klayout.db", "klayout.lay" etc.
|
||||||
|
The old combined Python module "pya" is still available, but deprecated in favor of
|
||||||
|
aligning code with the standalone "klayout" Python module.
|
||||||
|
The class and methods names are the same with very few exceptions and the documentation can be
|
||||||
used for Python too. Where necessary, a special remark is made regarding the Python implementation.
|
used for Python too. Where necessary, a special remark is made regarding the Python implementation.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
@ -68,12 +72,12 @@
|
||||||
<pre>
|
<pre>
|
||||||
# Python version:
|
# Python version:
|
||||||
|
|
||||||
import pya
|
import klayout.db as kdb
|
||||||
|
|
||||||
layout = pya.Layout()
|
layout = kdb.Layout()
|
||||||
top = layout.create_cell("TOP")
|
top = layout.create_cell("TOP")
|
||||||
l1 = layout.layer(1, 0)
|
l1 = layout.layer(1, 0)
|
||||||
top.shapes(l1).insert(pya.Box(0, 0, 1000, 2000))
|
top.shapes(l1).insert(kdb.Box(0, 0, 1000, 2000))
|
||||||
|
|
||||||
layout.write("t.gds")
|
layout.write("t.gds")
|
||||||
</pre>
|
</pre>
|
||||||
|
|
@ -139,7 +143,12 @@ layout.write("t.gds")
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>KLayout module:</b>
|
<li><b>KLayout module:</b>
|
||||||
KLayout's module is "pya" (lowercase conforming to PEP 8).
|
KLayout's module is "klayout" (lowercase conforming to PEP 8).
|
||||||
|
It has a number of submodules: "db", "lay", "pex", "rdb", "tl" and optionally
|
||||||
|
"QtCore", "QtGui" etc.
|
||||||
|
The built-in documentation mentiones the module containing a specific class
|
||||||
|
at the top of the class documentation. For example, "Box" is present in the
|
||||||
|
"db" submodule - i.e. it is present in "klayout.db".
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><b>Reserved names:</b>
|
<li><b>Reserved names:</b>
|
||||||
|
|
@ -154,8 +163,9 @@ layout.write("t.gds")
|
||||||
Assignment methods (i.e. "Box#left=" are available as attributes. If there is a
|
Assignment methods (i.e. "Box#left=" are available as attributes. If there is a
|
||||||
read accessor method too, the attribute can be read and written. For example:
|
read accessor method too, the attribute can be read and written. For example:
|
||||||
|
|
||||||
<pre>
|
<pre>import klayout.db as kdb
|
||||||
box = pya.Box()
|
|
||||||
|
box = kdb.Box()
|
||||||
box.left = 10
|
box.left = 10
|
||||||
box.right = box.right + 100
|
box.right = box.right + 100
|
||||||
</pre>
|
</pre>
|
||||||
|
|
@ -200,8 +210,9 @@ box.right = box.right + 100
|
||||||
<li><b>Iterators:</b>
|
<li><b>Iterators:</b>
|
||||||
Iterator binding:
|
Iterator binding:
|
||||||
|
|
||||||
<pre>
|
<pre>import klayout.db as kdb
|
||||||
edges = pya.Edges()
|
|
||||||
|
edges = kdb.Edges()
|
||||||
...
|
...
|
||||||
for edge in edges.each():
|
for edge in edges.each():
|
||||||
...
|
...
|
||||||
|
|
@ -221,8 +232,10 @@ for edge in edges:
|
||||||
|
|
||||||
<p>Most methods support keyword arguments, for example:</p>
|
<p>Most methods support keyword arguments, for example:</p>
|
||||||
|
|
||||||
<pre># a 45 degree rotation
|
<pre>import klayout.db as kdb
|
||||||
t = pya.CplxTrans(rot = 45)</pre>
|
|
||||||
|
# a 45 degree rotation
|
||||||
|
t = kdb.CplxTrans(rot = 45)</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Exceptions are some built-in methods like "assign". Keyword arguments can be used
|
Exceptions are some built-in methods like "assign". Keyword arguments can be used
|
||||||
|
|
@ -257,10 +270,11 @@ t = pya.CplxTrans(rot = 45)</pre>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li><b>Deep copies:</b>
|
<li><b>Deep copies:</b>
|
||||||
Deep copies of pya objects can be made with dup()
|
Deep copies of klayout objects can be made with dup()
|
||||||
|
|
||||||
<pre>
|
<pre>import klayout.db as kdb
|
||||||
box = pya.Box(10, 20, 110, 220)
|
|
||||||
|
box = kdb.Box(10, 20, 110, 220)
|
||||||
copy_box = box.dup()
|
copy_box = box.dup()
|
||||||
</pre>
|
</pre>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
<group-name/>
|
<group-name/>
|
||||||
<menu-path/>
|
<menu-path/>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<text>import pya
|
<text>
|
||||||
|
import pya
|
||||||
|
|
||||||
def _qt_signal(s):
|
def _qt_signal(s):
|
||||||
"""
|
"""
|
||||||
|
|
@ -39,9 +40,16 @@ def _getattr_with_child_objects(s, n):
|
||||||
# If Qt binding is enabled, install the new getattr function.
|
# If Qt binding is enabled, install the new getattr function.
|
||||||
# Also install the qt_signal and qt_slot functions which go into the pya module.
|
# Also install the qt_signal and qt_slot functions which go into the pya module.
|
||||||
if "QObject_Native" in pya.__dict__:
|
if "QObject_Native" in pya.__dict__:
|
||||||
|
|
||||||
pya.QObject_Native.__getattr__ = _getattr_with_child_objects
|
pya.QObject_Native.__getattr__ = _getattr_with_child_objects
|
||||||
pya.__dict__["qt_signal"] = _qt_signal
|
pya.__dict__["qt_signal"] = _qt_signal
|
||||||
pya.__dict__["qt_slot"] = _qt_slot
|
pya.__dict__["qt_slot"] = _qt_slot
|
||||||
|
|
||||||
|
# Do the same for klayout.QtCore
|
||||||
|
import klayout.QtCore
|
||||||
|
klayout.QtCore.QObject_Native.__getattr__ = _getattr_with_child_objects
|
||||||
|
klayout.QtCore.__dict__["qt_signal"] = _qt_signal
|
||||||
|
klayout.QtCore.__dict__["qt_slot"] = _qt_slot
|
||||||
|
|
||||||
</text>
|
</text>
|
||||||
</klayout-macro>
|
</klayout-macro>
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,16 @@
|
||||||
# Register this macro as "autorun" to enable the plugin
|
# Register this macro as "autorun" to enable the plugin
|
||||||
# on startup.
|
# on startup.
|
||||||
|
|
||||||
|
from klayout.lay import EditorOptionsPage, ConfigPage, Plugin, PluginFactory, MainWindow, Marker
|
||||||
|
from klayout.db import DBox, DPoint
|
||||||
|
from klayout.QtWidgets import QGridLayout, QVBoxLayout, QHBoxLayout, QLabel, QSpinBox, QLineEdit
|
||||||
|
|
||||||
cfg_color = "drag-box-color"
|
cfg_color = "drag-box-color"
|
||||||
cfg_width = "drag-box-width"
|
cfg_width = "drag-box-width"
|
||||||
|
|
||||||
# The widget placed into the editor options dock
|
# The widget placed into the editor options dock
|
||||||
|
|
||||||
class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
|
class DragBoxEditorOptionsPage(EditorOptionsPage):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
An option page providing a single entry box for configuring the line width
|
An option page providing a single entry box for configuring the line width
|
||||||
|
|
@ -47,12 +51,12 @@ class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
|
||||||
|
|
||||||
super(DragBoxEditorOptionsPage, self).__init__("Options", 1)
|
super(DragBoxEditorOptionsPage, self).__init__("Options", 1)
|
||||||
|
|
||||||
layout2 = pya.QVBoxLayout(self)
|
layout2 = QVBoxLayout(self)
|
||||||
layout = pya.QHBoxLayout(self)
|
layout = QHBoxLayout(self)
|
||||||
layout2.addLayout(layout)
|
layout2.addLayout(layout)
|
||||||
label = pya.QLabel("Line width", self)
|
label = QLabel("Line width", self)
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
self.spin_box = pya.QSpinBox(self)
|
self.spin_box = QSpinBox(self)
|
||||||
self.spin_box.setMinimum(1)
|
self.spin_box.setMinimum(1)
|
||||||
self.spin_box.setMaximum(16)
|
self.spin_box.setMaximum(16)
|
||||||
layout.addWidget(self.spin_box)
|
layout.addWidget(self.spin_box)
|
||||||
|
|
@ -87,7 +91,7 @@ class DragBoxEditorOptionsPage(pya.EditorOptionsPage):
|
||||||
|
|
||||||
# The modal dialog page that appears when "Tab" is pressed
|
# The modal dialog page that appears when "Tab" is pressed
|
||||||
|
|
||||||
class DragBoxFocusPage(pya.EditorOptionsPage):
|
class DragBoxFocusPage(EditorOptionsPage):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A (modal) option page, also called a "focus page". This page is
|
A (modal) option page, also called a "focus page". This page is
|
||||||
|
|
@ -115,21 +119,21 @@ class DragBoxFocusPage(pya.EditorOptionsPage):
|
||||||
self.focus_page = True
|
self.focus_page = True
|
||||||
self.modal_page = True
|
self.modal_page = True
|
||||||
|
|
||||||
self.box = pya.DBox()
|
self.box = DBox()
|
||||||
self.pfix = pya.DPoint()
|
self.pfix = DPoint()
|
||||||
self.update_box = None
|
self.update_box = None
|
||||||
|
|
||||||
layout = pya.QGridLayout(self)
|
layout = QGridLayout(self)
|
||||||
layout.setColumnStretch(1, 1)
|
layout.setColumnStretch(1, 1)
|
||||||
|
|
||||||
label = pya.QLabel("Width", self)
|
label = QLabel("Width", self)
|
||||||
layout.addWidget(label, 0, 0, 1, 1)
|
layout.addWidget(label, 0, 0, 1, 1)
|
||||||
self.le_width = pya.QLineEdit(self)
|
self.le_width = QLineEdit(self)
|
||||||
layout.addWidget(self.le_width, 0, 1, 1, 1)
|
layout.addWidget(self.le_width, 0, 1, 1, 1)
|
||||||
|
|
||||||
label = pya.QLabel("Height", self)
|
label = QLabel("Height", self)
|
||||||
layout.addWidget(label, 1, 0, 1, 1)
|
layout.addWidget(label, 1, 0, 1, 1)
|
||||||
self.le_height = pya.QLineEdit(self)
|
self.le_height = QLineEdit(self)
|
||||||
layout.addWidget(self.le_height, 1, 1, 1, 1)
|
layout.addWidget(self.le_height, 1, 1, 1, 1)
|
||||||
|
|
||||||
layout.setRowStretch(2, 1)
|
layout.setRowStretch(2, 1)
|
||||||
|
|
@ -175,11 +179,11 @@ class DragBoxFocusPage(pya.EditorOptionsPage):
|
||||||
|
|
||||||
# issue the event (call the handler) to inform the plugin of this change
|
# issue the event (call the handler) to inform the plugin of this change
|
||||||
if self.update_box is not None:
|
if self.update_box is not None:
|
||||||
self.update_box(pya.DBox(l, b, r, t))
|
self.update_box(DBox(l, b, r, t))
|
||||||
|
|
||||||
# The widget placed into the configuration page
|
# The widget placed into the configuration page
|
||||||
|
|
||||||
class DragBoxConfigPage(pya.ConfigPage):
|
class DragBoxConfigPage(ConfigPage):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A configuration page with a single entry box to change
|
A configuration page with a single entry box to change
|
||||||
|
|
@ -197,10 +201,10 @@ class DragBoxConfigPage(pya.ConfigPage):
|
||||||
|
|
||||||
super(DragBoxConfigPage, self).__init__("Drag Box|Configure")
|
super(DragBoxConfigPage, self).__init__("Drag Box|Configure")
|
||||||
|
|
||||||
layout = pya.QHBoxLayout(self)
|
layout = QHBoxLayout(self)
|
||||||
label = pya.QLabel("Color (hex, rrggbb)", self)
|
label = QLabel("Color (hex, rrggbb)", self)
|
||||||
layout.addWidget(label)
|
layout.addWidget(label)
|
||||||
self.line_edit = pya.QLineEdit(self)
|
self.line_edit = QLineEdit(self)
|
||||||
layout.addWidget(self.line_edit)
|
layout.addWidget(self.line_edit)
|
||||||
layout.addStretch(1)
|
layout.addStretch(1)
|
||||||
|
|
||||||
|
|
@ -217,7 +221,7 @@ class DragBoxConfigPage(pya.ConfigPage):
|
||||||
"""
|
"""
|
||||||
dispatcher.set_config(cfg_color, self.line_edit.text)
|
dispatcher.set_config(cfg_color, self.line_edit.text)
|
||||||
|
|
||||||
class DragBoxPlugin(pya.Plugin):
|
class DragBoxPlugin(Plugin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The custom plugin implementation.
|
The custom plugin implementation.
|
||||||
|
|
@ -275,14 +279,14 @@ class DragBoxPlugin(pya.Plugin):
|
||||||
self.marker = None
|
self.marker = None
|
||||||
# reset to idle
|
# reset to idle
|
||||||
self.ungrab_mouse()
|
self.ungrab_mouse()
|
||||||
pya.MainWindow.instance().message("Box finished: " + str(self.box), 10000)
|
MainWindow.instance().message("Box finished: " + str(self.box), 10000)
|
||||||
|
|
||||||
def _update_marker(self):
|
def _update_marker(self):
|
||||||
"""
|
"""
|
||||||
updates the marker with the current box
|
updates the marker with the current box
|
||||||
"""
|
"""
|
||||||
if self.marker is None:
|
if self.marker is None:
|
||||||
self.marker = pya.Marker(self.view)
|
self.marker = Marker(self.view)
|
||||||
self._configure_marker()
|
self._configure_marker()
|
||||||
self.marker.set(self.box)
|
self.marker.set(self.box)
|
||||||
|
|
||||||
|
|
@ -339,7 +343,7 @@ class DragBoxPlugin(pya.Plugin):
|
||||||
plugin is activated - i.e. the mode is selected
|
plugin is activated - i.e. the mode is selected
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pya.MainWindow.instance().message("Click on point to start dragging a box", 10000)
|
MainWindow.instance().message("Click on point to start dragging a box", 10000)
|
||||||
|
|
||||||
def deactivated(self):
|
def deactivated(self):
|
||||||
|
|
||||||
|
|
@ -349,7 +353,7 @@ class DragBoxPlugin(pya.Plugin):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._clear_marker()
|
self._clear_marker()
|
||||||
pya.MainWindow.instance().message("", 0)
|
MainWindow.instance().message("", 0)
|
||||||
|
|
||||||
def mouse_click_event(self, p, buttons, prio):
|
def mouse_click_event(self, p, buttons, prio):
|
||||||
|
|
||||||
|
|
@ -363,15 +367,15 @@ class DragBoxPlugin(pya.Plugin):
|
||||||
# stop dragging it and freeze the box
|
# stop dragging it and freeze the box
|
||||||
if self.marker is None:
|
if self.marker is None:
|
||||||
p = self.snap2(p)
|
p = self.snap2(p)
|
||||||
self.box = pya.DBox(p, p)
|
self.box = DBox(p, p)
|
||||||
self.start_point = p
|
self.start_point = p
|
||||||
self._clear_marker()
|
self._clear_marker()
|
||||||
self._update_marker()
|
self._update_marker()
|
||||||
self.grab_mouse()
|
self.grab_mouse()
|
||||||
pya.MainWindow.instance().message("Drag the box and click again", 10000)
|
MainWindow.instance().message("Drag the box and click again", 10000)
|
||||||
else:
|
else:
|
||||||
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons))
|
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons))
|
||||||
self._update_box(pya.DBox(self.start_point, p))
|
self._update_box(DBox(self.start_point, p))
|
||||||
self._finish()
|
self._finish()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
@ -395,13 +399,13 @@ class DragBoxPlugin(pya.Plugin):
|
||||||
self.clear_mouse_cursors()
|
self.clear_mouse_cursors()
|
||||||
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons), visualize=True)
|
p = self.snap2(p, self.start_point, True, self.ac_from_buttons(buttons), visualize=True)
|
||||||
self.add_mouse_cursor(p)
|
self.add_mouse_cursor(p)
|
||||||
self.box = pya.DBox(self.start_point, p)
|
self.box = DBox(self.start_point, p)
|
||||||
self._update_marker()
|
self._update_marker()
|
||||||
# NOTE: we must not digest this event (i.e. return True)
|
# NOTE: we must not digest this event (i.e. return True)
|
||||||
# to allow the mouse tracker to receive the events as well
|
# to allow the mouse tracker to receive the events as well
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class DragBoxPluginFactory(pya.PluginFactory):
|
class DragBoxPluginFactory(PluginFactory):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Implements a "plugin factory".
|
Implements a "plugin factory".
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
<show-in-menu>false</show-in-menu>
|
<show-in-menu>false</show-in-menu>
|
||||||
<category>pymacros</category>
|
<category>pymacros</category>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<text>import pya
|
<text>import klayout.db as kdb
|
||||||
|
import klayout.lay as klay
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This demo installs editor hooks to indicate the forbidding regions around a shape
|
This demo installs editor hooks to indicate the forbidding regions around a shape
|
||||||
|
|
@ -24,7 +25,7 @@ are drawn.
|
||||||
Space between instances: 0.4
|
Space between instances: 0.4
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class MyEditorHooks(pya.EditorHooks):
|
class MyEditorHooks(klay.EditorHooks):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
|
@ -36,9 +37,9 @@ class MyEditorHooks(pya.EditorHooks):
|
||||||
self.space = 0.0
|
self.space = 0.0
|
||||||
|
|
||||||
self.spaces = {
|
self.spaces = {
|
||||||
pya.LayerInfo(1, 0): ( 0.2, pya.Region.Euclidian ),
|
kdb.LayerInfo(1, 0): ( 0.2, kdb.Region.Euclidian ),
|
||||||
pya.LayerInfo(2, 0): ( 0.5, pya.Region.Projection ),
|
kdb.LayerInfo(2, 0): ( 0.5, kdb.Region.Projection ),
|
||||||
pya.LayerInfo(3, 0): ( 1.0, pya.Region.Projection )
|
kdb.LayerInfo(3, 0): ( 1.0, kdb.Region.Projection )
|
||||||
}
|
}
|
||||||
|
|
||||||
self.instance_space = 0.4
|
self.instance_space = 0.4
|
||||||
|
|
@ -61,12 +62,12 @@ class MyEditorHooks(pya.EditorHooks):
|
||||||
|
|
||||||
p = shape.polygon
|
p = shape.polygon
|
||||||
if p is not None and p.num_points() < 100:
|
if p is not None and p.num_points() < 100:
|
||||||
r = pya.Region()
|
r = kdb.Region()
|
||||||
r.merged_semantics = (p.num_points() != 2)
|
r.merged_semantics = (p.num_points() != 2)
|
||||||
r.insert(p)
|
r.insert(p)
|
||||||
r = r.drc_hull(self.metrics, self.space)
|
r = r.drc_hull(self.metrics, self.space)
|
||||||
for pp in r.each():
|
for pp in r.each():
|
||||||
m = pya.Marker(self.view)
|
m = klay.Marker(self.view)
|
||||||
m.line_style = 2
|
m.line_style = 2
|
||||||
m.vertex_size = 0
|
m.vertex_size = 0
|
||||||
m.set_polygon(trans * pp)
|
m.set_polygon(trans * pp)
|
||||||
|
|
@ -74,7 +75,7 @@ class MyEditorHooks(pya.EditorHooks):
|
||||||
|
|
||||||
t = shape.text
|
t = shape.text
|
||||||
if t is not None:
|
if t is not None:
|
||||||
m = pya.Marker(self.view)
|
m = klay.Marker(self.view)
|
||||||
m.set_box(trans * t.bbox().enlarged(self.space))
|
m.set_box(trans * t.bbox().enlarged(self.space))
|
||||||
self.markers.append(m)
|
self.markers.append(m)
|
||||||
|
|
||||||
|
|
@ -117,7 +118,7 @@ class MyEditorHooks(pya.EditorHooks):
|
||||||
self.markers = []
|
self.markers = []
|
||||||
|
|
||||||
def create_instance(self, instance, trans):
|
def create_instance(self, instance, trans):
|
||||||
m = pya.Marker(self.view)
|
m = klay.Marker(self.view)
|
||||||
m.set_box(trans * instance.bbox().enlarged(self.instance_space / self.layout.dbu))
|
m.set_box(trans * instance.bbox().enlarged(self.instance_space / self.layout.dbu))
|
||||||
self.markers.append(m)
|
self.markers.append(m)
|
||||||
|
|
||||||
|
|
@ -143,7 +144,7 @@ class MyEditorHooks(pya.EditorHooks):
|
||||||
|
|
||||||
if path.shape is None:
|
if path.shape is None:
|
||||||
|
|
||||||
m = pya.Marker(self.view)
|
m = klay.Marker(self.view)
|
||||||
m.set_box(trans * (applied * path.inst().bbox()).enlarged(self.instance_space / self.layout.dbu))
|
m.set_box(trans * (applied * path.inst().bbox()).enlarged(self.instance_space / self.layout.dbu))
|
||||||
self.markers.append(m)
|
self.markers.append(m)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
<shortcut/>
|
<shortcut/>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<category>pymacro</category>
|
<category>pymacro</category>
|
||||||
<text>import pya
|
<text>import klayout.db as kdb
|
||||||
|
import klayout.lay as klay
|
||||||
|
|
||||||
# Enter your Python code here ..
|
# Enter your Python code here ..
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,13 @@ module PCellLibModule
|
||||||
# In lazy mode, the user has to acknowledge parameter changes before
|
# In lazy mode, the user has to acknowledge parameter changes before
|
||||||
# they are executed.
|
# they are executed.
|
||||||
# end
|
# end
|
||||||
|
#
|
||||||
|
# optional:
|
||||||
|
# def callback_impl(name)
|
||||||
|
# TODO: implement functionality to change user interface element
|
||||||
|
# states for PCell parameter editors based on certain events
|
||||||
|
# like value changes.
|
||||||
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,15 @@
|
||||||
<show-in-menu>false</show-in-menu>
|
<show-in-menu>false</show-in-menu>
|
||||||
<shortcut></shortcut>
|
<shortcut></shortcut>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<text>import pya
|
<text>import klayout.db as kdb
|
||||||
|
|
||||||
# PCell template
|
# PCell template
|
||||||
# This macro template provides the framework for a PCell library
|
# This macro template provides the framework for a PCell library
|
||||||
|
|
||||||
# It is recommended to put PCell code into namespaces.
|
|
||||||
# TODO: change the module name
|
|
||||||
|
|
||||||
# The PCell declaration
|
# The PCell declaration
|
||||||
# Each PCell must provide a declaration. It is recommended to use the PCell name as the class name.
|
# Each PCell must provide a declaration. It is recommended to use the PCell name as the class name.
|
||||||
# TODO: change the class name
|
# TODO: change the class name
|
||||||
class PCell(pya.PCellDeclarationHelper):
|
class PCell(kdb.PCellDeclarationHelper):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
|
@ -26,8 +23,8 @@ class PCell(pya.PCellDeclarationHelper):
|
||||||
super(PCell, self).__init__()
|
super(PCell, self).__init__()
|
||||||
|
|
||||||
# declare the parameters
|
# declare the parameters
|
||||||
# i.e. self.param("l", self.TypeLayer, "Layer", default = pya.LayerInfo(1, 0))
|
# i.e. self.param("l", self.TypeLayer, "Layer", default = kdb.LayerInfo(1, 0))
|
||||||
# self.param("s", self.TypeShape, "", default = pya.DPoint(0, 0))
|
# self.param("s", self.TypeShape, "", default = kdb.DPoint(0, 0))
|
||||||
|
|
||||||
def display_text_impl(self):
|
def display_text_impl(self):
|
||||||
# Provide a descriptive text for the cell
|
# Provide a descriptive text for the cell
|
||||||
|
|
@ -35,10 +32,12 @@ class PCell(pya.PCellDeclarationHelper):
|
||||||
|
|
||||||
def coerce_parameters_impl(self):
|
def coerce_parameters_impl(self):
|
||||||
# TODO: use x to access parameter x and set_x to modify its value
|
# TODO: use x to access parameter x and set_x to modify its value
|
||||||
|
pass
|
||||||
|
|
||||||
def produce_impl(self):
|
def produce_impl(self):
|
||||||
# TODO: produce the cell content
|
# TODO: produce the cell content
|
||||||
# i.e. self.cell.shapes(self.l_layer).insert(pya.Polygon(...))
|
# i.e. self.cell.shapes(self.l_layer).insert(kdb.Polygon(...))
|
||||||
|
pass
|
||||||
|
|
||||||
# optional:
|
# optional:
|
||||||
# def can_create_from_shape_impl(self):
|
# def can_create_from_shape_impl(self):
|
||||||
|
|
@ -60,6 +59,12 @@ class PCell(pya.PCellDeclarationHelper):
|
||||||
# TODO: return "True" here if the PCell takes a long time to compute.
|
# TODO: return "True" here if the PCell takes a long time to compute.
|
||||||
# In lazy mode, the user has to acknowledge parameter changes before
|
# In lazy mode, the user has to acknowledge parameter changes before
|
||||||
# they are executed.
|
# they are executed.
|
||||||
|
#
|
||||||
|
# optional:
|
||||||
|
# def callback_impl(self, name):
|
||||||
|
# TODO: implement functionality to change user interface element
|
||||||
|
# states for PCell parameter editors based on certain events
|
||||||
|
# like value changes.
|
||||||
|
|
||||||
# TODO: add more PCell classes ..
|
# TODO: add more PCell classes ..
|
||||||
|
|
||||||
|
|
@ -68,7 +73,7 @@ class PCell(pya.PCellDeclarationHelper):
|
||||||
# The main purpose of this class is to provide the PCell declarations and to register itself
|
# The main purpose of this class is to provide the PCell declarations and to register itself
|
||||||
# with a proper name.
|
# with a proper name.
|
||||||
# TODO: change the class name
|
# TODO: change the class name
|
||||||
class PCellLib(pya.Library):
|
class PCellLib(kdb.Library):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<shortcut></shortcut>
|
<shortcut></shortcut>
|
||||||
<category>pymacros</category>
|
<category>pymacros</category>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<text>import pya
|
<text>import klayout.db as kdb
|
||||||
import math
|
import math
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
@ -22,7 +22,7 @@ implementation. The macro is also set to "auto run" to install the PCell
|
||||||
when KLayout is run.
|
when KLayout is run.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Circle(pya.PCellDeclarationHelper):
|
class Circle(kdb.PCellDeclarationHelper):
|
||||||
"""
|
"""
|
||||||
The PCell declaration for the circle
|
The PCell declaration for the circle
|
||||||
"""
|
"""
|
||||||
|
|
@ -34,7 +34,7 @@ class Circle(pya.PCellDeclarationHelper):
|
||||||
|
|
||||||
# declare the parameters
|
# declare the parameters
|
||||||
self.param("l", self.TypeLayer, "Layer")
|
self.param("l", self.TypeLayer, "Layer")
|
||||||
self.param("s", self.TypeShape, "", default = pya.DPoint(0, 0))
|
self.param("s", self.TypeShape, "", default = kdb.DPoint(0, 0))
|
||||||
self.param("r", self.TypeDouble, "Radius", default = 0.1)
|
self.param("r", self.TypeDouble, "Radius", default = 0.1)
|
||||||
self.param("n", self.TypeInt, "Number of points", default = 64)
|
self.param("n", self.TypeInt, "Number of points", default = 64)
|
||||||
# this hidden parameter is used to determine whether the radius has changed
|
# this hidden parameter is used to determine whether the radius has changed
|
||||||
|
|
@ -53,15 +53,15 @@ class Circle(pya.PCellDeclarationHelper):
|
||||||
# radius ru) and set ru to the effective radius. We also update the
|
# radius ru) and set ru to the effective radius. We also update the
|
||||||
# numerical value or the shape, depending on which on has not changed.
|
# numerical value or the shape, depending on which on has not changed.
|
||||||
rs = None
|
rs = None
|
||||||
if isinstance(self.s, pya.DPoint):
|
if isinstance(self.s, kdb.DPoint):
|
||||||
# compute distance in micron
|
# compute distance in micron
|
||||||
rs = self.s.distance(pya.DPoint(0, 0))
|
rs = self.s.distance(kdb.DPoint(0, 0))
|
||||||
if rs != None and abs(self.r-self.ru) < 1e-6:
|
if rs != None and abs(self.r-self.ru) < 1e-6:
|
||||||
self.ru = rs
|
self.ru = rs
|
||||||
self.r = rs
|
self.r = rs
|
||||||
else:
|
else:
|
||||||
self.ru = self.r
|
self.ru = self.r
|
||||||
self.s = pya.DPoint(-self.r, 0)
|
self.s = kdb.DPoint(-self.r, 0)
|
||||||
|
|
||||||
self.rd = 2*self.r
|
self.rd = 2*self.r
|
||||||
|
|
||||||
|
|
@ -83,7 +83,7 @@ class Circle(pya.PCellDeclarationHelper):
|
||||||
def transformation_from_shape_impl(self):
|
def transformation_from_shape_impl(self):
|
||||||
# Implement the "Create PCell from shape" protocol: we use the center of the shape's
|
# Implement the "Create PCell from shape" protocol: we use the center of the shape's
|
||||||
# bounding box to determine the transformation
|
# bounding box to determine the transformation
|
||||||
return pya.Trans(self.shape.bbox().center())
|
return kdb.Trans(self.shape.bbox().center())
|
||||||
|
|
||||||
def produce_impl(self):
|
def produce_impl(self):
|
||||||
|
|
||||||
|
|
@ -91,13 +91,13 @@ class Circle(pya.PCellDeclarationHelper):
|
||||||
|
|
||||||
# compute the circle
|
# compute the circle
|
||||||
da = math.pi * 2 / self.n
|
da = math.pi * 2 / self.n
|
||||||
pts = [ pya.DPoint(self.ru * math.cos(i * da), self.ru * math.sin(i * da)) for i in range(0, self.n) ]
|
pts = [ kdb.DPoint(self.ru * math.cos(i * da), self.ru * math.sin(i * da)) for i in range(0, self.n) ]
|
||||||
|
|
||||||
# create the shape
|
# create the shape
|
||||||
self.cell.shapes(self.l_layer).insert(pya.DPolygon(pts))
|
self.cell.shapes(self.l_layer).insert(kdb.DPolygon(pts))
|
||||||
|
|
||||||
|
|
||||||
class MyLib(pya.Library):
|
class MyLib(kdb.Library):
|
||||||
"""
|
"""
|
||||||
The library where we will put the PCell into
|
The library where we will put the PCell into
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,16 @@
|
||||||
<group-name/>
|
<group-name/>
|
||||||
<menu-path/>
|
<menu-path/>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<text>import pya
|
<text>from klayout.QtUiTools import QUiLoader
|
||||||
|
from klayout.QtCore import QFile, QIODevice
|
||||||
|
from klayout.lay import Application
|
||||||
import types
|
import types
|
||||||
|
|
||||||
# Create the form object from the uic file:
|
# Create the form object from the uic file:
|
||||||
|
|
||||||
ui_file = pya.QFile(":/macro-templates/qt_designer.ui")
|
ui_file = QFile(":/macro-templates/qt_designer.ui")
|
||||||
ui_file.open(pya.QIODevice.ReadOnly)
|
ui_file.open(QIODevice.ReadOnly)
|
||||||
form = pya.QUiLoader().load(ui_file, pya.Application.instance().main_window())
|
form = QUiLoader().load(ui_file, Application.instance().main_window())
|
||||||
ui_file.close()
|
ui_file.close()
|
||||||
|
|
||||||
# Install an event handler for the button clicked event
|
# Install an event handler for the button clicked event
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,11 @@
|
||||||
<menu-path/>
|
<menu-path/>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<dsl-interpreter-name/>
|
<dsl-interpreter-name/>
|
||||||
<text>import pya
|
<text>from klayout.QtWidgets import QDialog, QVBoxLayout, QLabel, QPushButton
|
||||||
|
from klayout.QtGui import QPixmap, QFont
|
||||||
|
from klayout.lay import Application
|
||||||
|
|
||||||
class ScreenshotDialog(pya.QDialog):
|
class ScreenshotDialog(QDialog):
|
||||||
"""
|
"""
|
||||||
This class implements a dialog with a screenshot display area and a
|
This class implements a dialog with a screenshot display area and a
|
||||||
screenshot button
|
screenshot button
|
||||||
|
|
@ -25,11 +27,11 @@ class ScreenshotDialog(pya.QDialog):
|
||||||
def button_clicked(self, checked):
|
def button_clicked(self, checked):
|
||||||
""" Event handler: "Screenshot" button clicked """
|
""" Event handler: "Screenshot" button clicked """
|
||||||
|
|
||||||
view = pya.Application.instance().main_window().current_view()
|
view = Application.instance().main_window().current_view()
|
||||||
|
|
||||||
# get the screenshot and place it in the image label
|
# get the screenshot and place it in the image label
|
||||||
if not view is None:
|
if not view is None:
|
||||||
self.image.setPixmap(pya.QPixmap.fromImage(view.get_image(400, 400)))
|
self.image.setPixmap(QPixmap.fromImage(view.get_image(400, 400)))
|
||||||
else:
|
else:
|
||||||
self.image.setText("No layout opened to take screenshot from")
|
self.image.setText("No layout opened to take screenshot from")
|
||||||
|
|
||||||
|
|
@ -42,14 +44,14 @@ class ScreenshotDialog(pya.QDialog):
|
||||||
|
|
||||||
self.resize(400, 120)
|
self.resize(400, 120)
|
||||||
|
|
||||||
layout = pya.QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
self.image = pya.QLabel("Press the button to fetch a screenshot", self)
|
self.image = QLabel("Press the button to fetch a screenshot", self)
|
||||||
layout.addWidget(self.image)
|
layout.addWidget(self.image)
|
||||||
|
|
||||||
button = pya.QPushButton('Screenshot', self)
|
button = QPushButton('Screenshot', self)
|
||||||
button.setFont(pya.QFont('Times', 18, int(pya.QFont.Bold)))
|
button.setFont(QFont('Times', 18, int(QFont.Bold)))
|
||||||
layout.addWidget(button)
|
layout.addWidget(button)
|
||||||
|
|
||||||
# attach the event handler
|
# attach the event handler
|
||||||
|
|
@ -57,7 +59,7 @@ class ScreenshotDialog(pya.QDialog):
|
||||||
|
|
||||||
# Instantiate the dialog and make it visible initially.
|
# Instantiate the dialog and make it visible initially.
|
||||||
# Passing the main_window will make it stay on top of the main window.
|
# Passing the main_window will make it stay on top of the main window.
|
||||||
dialog = ScreenshotDialog(pya.Application.instance().main_window())
|
dialog = ScreenshotDialog(Application.instance().main_window())
|
||||||
dialog.show()
|
dialog.show()
|
||||||
</text>
|
</text>
|
||||||
</klayout-macro>
|
</klayout-macro>
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@
|
||||||
<menu-path/>
|
<menu-path/>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<dsl-interpreter-name/>
|
<dsl-interpreter-name/>
|
||||||
<text>import pya
|
<text>import re
|
||||||
import re
|
from klayout.QtNetwork import QTcpServer, QTcpSocket, QHostAddress
|
||||||
|
from klayout.QtCore import QUrl, QBuffer, QIODevice, QObject, qt_signal, qt_slot
|
||||||
|
from klayout.lay import Application
|
||||||
|
|
||||||
class MyServer(pya.QTcpServer):
|
class MyServer(QTcpServer):
|
||||||
"""
|
"""
|
||||||
Implements a TCP server listening on port 8082
|
Implements a TCP server listening on port 8082
|
||||||
This server will accept HTTP requests and deliver a HTML page containing an image
|
This server will accept HTTP requests and deliver a HTML page containing an image
|
||||||
|
|
@ -39,7 +41,7 @@ class MyServer(pya.QTcpServer):
|
||||||
connection = self.nextPendingConnection()
|
connection = self.nextPendingConnection()
|
||||||
|
|
||||||
# Read the request header
|
# Read the request header
|
||||||
while connection.isOpen() and connection.state() == pya.QTcpSocket.ConnectedState:
|
while connection.isOpen() and connection.state() == QTcpSocket.ConnectedState:
|
||||||
if connection.canReadLine():
|
if connection.canReadLine():
|
||||||
line = connection.readLine().decode("utf-8")
|
line = connection.readLine().decode("utf-8")
|
||||||
if line.rstrip('\n').rstrip('\r') == "":
|
if line.rstrip('\n').rstrip('\r') == "":
|
||||||
|
|
@ -47,19 +49,19 @@ class MyServer(pya.QTcpServer):
|
||||||
else:
|
else:
|
||||||
m = re.match("GET\\s+(.*)\\s+HTTP", line)
|
m = re.match("GET\\s+(.*)\\s+HTTP", line)
|
||||||
if not m is None:
|
if not m is None:
|
||||||
url = pya.QUrl(m.groups()[0])
|
url = QUrl(m.groups()[0])
|
||||||
else:
|
else:
|
||||||
connection.waitForReadyRead(100)
|
connection.waitForReadyRead(100)
|
||||||
|
|
||||||
view = pya.Application.instance().main_window().current_view()
|
view = Application.instance().main_window().current_view()
|
||||||
|
|
||||||
if url is None:
|
if url is None:
|
||||||
pass
|
pass
|
||||||
elif url.path == "/screenshot.png":
|
elif url.path() == "/screenshot.png":
|
||||||
# Deliver the image
|
# Deliver the image
|
||||||
if not view is None:
|
if not view is None:
|
||||||
b = pya.QBuffer()
|
b = QBuffer()
|
||||||
b.open(pya.QIODevice.WriteOnly)
|
b.open(QIODevice.WriteOnly)
|
||||||
view.get_image(800, 800).save(b, "PNG")
|
view.get_image(800, 800).save(b, "PNG")
|
||||||
b.close()
|
b.close()
|
||||||
connection.write(b.buffer())
|
connection.write(b.buffer())
|
||||||
|
|
@ -70,13 +72,13 @@ class MyServer(pya.QTcpServer):
|
||||||
connection.write("HTTP/1.0 200 OK\nContent-Type: text/html\n\n" + '<html><body>No view open to take screenshot from</body></html>\n\n')
|
connection.write("HTTP/1.0 200 OK\nContent-Type: text/html\n\n" + '<html><body>No view open to take screenshot from</body></html>\n\n')
|
||||||
|
|
||||||
# automatically delete when disconnected
|
# automatically delete when disconnected
|
||||||
# Note: we cannot use RBA signal bindings for that purpose because the Ruby object might get
|
# Note: we cannot use native Python signal bindings for that purpose because the Python object might get
|
||||||
# deleted before the C++ object is. Hence we do it explicitly.
|
# deleted before the C++ object is. Hence we do it explicitly.
|
||||||
connection.disconnectFromHost()
|
connection.disconnectFromHost()
|
||||||
#connection.destroy()
|
#connection.destroy()
|
||||||
signal = pya.qt_signal("disconnected()")
|
signal = qt_signal("disconnected()")
|
||||||
slot = pya.qt_slot("deleteLater()")
|
slot = qt_slot("deleteLater()")
|
||||||
pya.QObject.connect(connection, signal, connection, slot)
|
QObject.connect(connection, signal, connection, slot)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("ERROR " + str(ex))
|
print("ERROR " + str(ex))
|
||||||
|
|
@ -89,7 +91,7 @@ class MyServer(pya.QTcpServer):
|
||||||
|
|
||||||
super(MyServer, self).__init__(parent)
|
super(MyServer, self).__init__(parent)
|
||||||
|
|
||||||
ha = pya.QHostAddress("0.0.0.0")
|
ha = QHostAddress("0.0.0.0")
|
||||||
self.listen(ha, 8082)
|
self.listen(ha, 8082)
|
||||||
|
|
||||||
# install an event on a new connection
|
# install an event on a new connection
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<show-in-menu>false</show-in-menu>
|
<show-in-menu>false</show-in-menu>
|
||||||
<category>pymacros</category>
|
<category>pymacros</category>
|
||||||
<interpreter>python</interpreter>
|
<interpreter>python</interpreter>
|
||||||
<text>import pya
|
<text>import klayout.db as kdb
|
||||||
import math
|
import math
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
@ -33,7 +33,7 @@ implementation. The macro is also set to "auto run" to install the PCell
|
||||||
when KLayout is run.
|
when KLayout is run.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class ViaPCell(pya.PCellDeclarationHelper):
|
class ViaPCell(kdb.PCellDeclarationHelper):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
|
@ -73,18 +73,18 @@ class ViaPCell(pya.PCellDeclarationHelper):
|
||||||
self.via_type_list = []
|
self.via_type_list = []
|
||||||
|
|
||||||
# Via1
|
# Via1
|
||||||
vt = pya.ViaType("V1", "Via1 (0.2x0.2)")
|
vt = kdb.ViaType("V1", "Via1 (0.2x0.2)")
|
||||||
vt.wbmin = 0.4
|
vt.wbmin = 0.4
|
||||||
vt.hbmin = 0.4
|
vt.hbmin = 0.4
|
||||||
vt.wtmin = 0.5
|
vt.wtmin = 0.5
|
||||||
vt.htmin = 0.5
|
vt.htmin = 0.5
|
||||||
vt.bottom = pya.LayerInfo(1, 0)
|
vt.bottom = kdb.LayerInfo(1, 0)
|
||||||
vt.cut = pya.LayerInfo(2, 0)
|
vt.cut = kdb.LayerInfo(2, 0)
|
||||||
vt.top = pya.LayerInfo(3, 0)
|
vt.top = kdb.LayerInfo(3, 0)
|
||||||
vt.bottom_grid = 0.01
|
vt.bottom_grid = 0.01
|
||||||
vt.top_grid = 0.01
|
vt.top_grid = 0.01
|
||||||
|
|
||||||
# foreign attributes (not used by pya, but handy for
|
# foreign attributes (not used by KLayout, but handy for
|
||||||
# internal use):
|
# internal use):
|
||||||
vt.enc_bottom = 0.1
|
vt.enc_bottom = 0.1
|
||||||
vt.enc_top = 0.15
|
vt.enc_top = 0.15
|
||||||
|
|
@ -94,18 +94,18 @@ class ViaPCell(pya.PCellDeclarationHelper):
|
||||||
self.via_type_list.append(vt)
|
self.via_type_list.append(vt)
|
||||||
|
|
||||||
# Via2
|
# Via2
|
||||||
vt = pya.ViaType("V2", "Via2 (0.3x0.3)")
|
vt = kdb.ViaType("V2", "Via2 (0.3x0.3)")
|
||||||
vt.wbmin = 0.5
|
vt.wbmin = 0.5
|
||||||
vt.hbmin = 0.5
|
vt.hbmin = 0.5
|
||||||
vt.wtmin = 0.5
|
vt.wtmin = 0.5
|
||||||
vt.htmin = 0.5
|
vt.htmin = 0.5
|
||||||
vt.bottom = pya.LayerInfo(3, 0)
|
vt.bottom = kdb.LayerInfo(3, 0)
|
||||||
vt.cut = pya.LayerInfo(4, 0)
|
vt.cut = kdb.LayerInfo(4, 0)
|
||||||
vt.top = pya.LayerInfo(5, 0)
|
vt.top = kdb.LayerInfo(5, 0)
|
||||||
vt.bottom_grid = 0.01
|
vt.bottom_grid = 0.01
|
||||||
vt.top_grid = 0.01
|
vt.top_grid = 0.01
|
||||||
|
|
||||||
# foreign attributes (not used by pya, but handy for
|
# foreign attributes (not used by kdb, but handy for
|
||||||
# internal use):
|
# internal use):
|
||||||
vt.enc_bottom = 0.1
|
vt.enc_bottom = 0.1
|
||||||
vt.enc_top = 0.1
|
vt.enc_top = 0.1
|
||||||
|
|
@ -159,7 +159,7 @@ class ViaPCell(pya.PCellDeclarationHelper):
|
||||||
"""
|
"""
|
||||||
PCell interface implementation
|
PCell interface implementation
|
||||||
"""
|
"""
|
||||||
return pya.Trans()
|
return kdb.Trans()
|
||||||
|
|
||||||
def min_dim(self, a, b, da, db):
|
def min_dim(self, a, b, da, db):
|
||||||
"""
|
"""
|
||||||
|
|
@ -248,8 +248,8 @@ class ViaPCell(pya.PCellDeclarationHelper):
|
||||||
ltop = self.layout.layer(vt.top)
|
ltop = self.layout.layer(vt.top)
|
||||||
lcut = self.layout.layer(vt.cut)
|
lcut = self.layout.layer(vt.cut)
|
||||||
|
|
||||||
self.cell.shapes(lbottom).insert(pya.DBox(wbottom, hbottom))
|
self.cell.shapes(lbottom).insert(kdb.DBox(wbottom, hbottom))
|
||||||
self.cell.shapes(ltop).insert(pya.DBox(wtop, htop))
|
self.cell.shapes(ltop).insert(kdb.DBox(wtop, htop))
|
||||||
|
|
||||||
scut = self.cell.shapes(lcut)
|
scut = self.cell.shapes(lcut)
|
||||||
|
|
||||||
|
|
@ -257,10 +257,10 @@ class ViaPCell(pya.PCellDeclarationHelper):
|
||||||
x = (ix - 0.5 * (nx - 1)) * (vt.vwidth + vt.vspace)
|
x = (ix - 0.5 * (nx - 1)) * (vt.vwidth + vt.vspace)
|
||||||
for iy in range(0, ny):
|
for iy in range(0, ny):
|
||||||
y = (iy - 0.5 * (ny - 1)) * (vt.vwidth + vt.vspace)
|
y = (iy - 0.5 * (ny - 1)) * (vt.vwidth + vt.vspace)
|
||||||
scut.insert(pya.DBox(vt.vwidth, vt.vwidth).moved(x, y))
|
scut.insert(kdb.DBox(vt.vwidth, vt.vwidth).moved(x, y))
|
||||||
|
|
||||||
|
|
||||||
class MyViaLib(pya.Library):
|
class MyViaLib(kdb.Library):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A declaration for a test library
|
A declaration for a test library
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue