Build layer index on empty layout

edited March 2018 in Python scripting

I'm reading a pre-defined layer .lyp file into Klayout and run readLayer() to fill a WidgetTable form.
Issues I would like to solve is that if a layer index doesn't exist I can't set the layer properties.
Only if I create a new layer or a layer is used already to draw a shape the layer is recognized.

Is there a method to build a layer index with an empty layout and an imported .lyp?
Thanks in advance for your valued feedback.

Andy

def readLayer(): 
 config()
  lv.add_missing_layers()
  lv.update_content
  Liter = lv.begin_layers()
  while not Liter.at_end():
      lp = Liter.current()
      if(lp.layer_index()>= 0 ):       # required because otherwise the procedure will crash if no valid layer index exist
        info = layout.get_info(lp.layer_index())
        #print('Selected Layer:', info.name, info.layer, info.datatype)
        numRows = dialog.tW.rowCount
        dialog.tW.insertRow(numRows)
        dialog.tW.setItem(numRows,0,QTableWidgetItem(str(info.name)))
        dialog.tW.setItem(numRows,1,QTableWidgetItem(str(info.layer)))
        dialog.tW.setItem(numRows,2,QTableWidgetItem(str(info.datatype)))
      Liter.next()

Comments

  • edited March 2018

    Hi Any,

    there is one issue here: the .lyp file specifies a "source" which may be only partially specified. If for example, the source gives the layer and datatype, the name can only be obtained after the layout way read and this name can be taken from the database. If no such layer is there, you can use the intended layer:

    if lp.layer_index() >= 0:
      ...
    else:
      ...
      dialog.tW.setItem(numRows,0,QTableWidgetItem(str(lp.source_name)))
      dialog.tW.setItem(numRows,1,QTableWidgetItem(str(lp.source_layer)))
      dialog.tW.setItem(numRows,2,QTableWidgetItem(str(lp.source_datatype)))
    

    If you're just interested in what the .lyp file will tell you, just use "lp.source_..." instead of asking the layout object.

    Regards,

    Matthias

  • edited November -1

    Thanks a lot Matthias,
    works perfect ...

    Reason for this implemetation is that the klayout user would like have a quick way to add a layer name and changing the datatype. You could do this with KL functionalty but only layer per layer. The following script uses a tableWidget to run it in one step.

    from pya import *
    
    import sys
    import types
    from os.path import curdir, join
    
    def config():
      global lv, layout, cellview, layerFile
    
      lv = pya.Application.instance().main_window().current_view()
      if lv == None:
        raise Exception("No view selected")
    
    # Find the currently selected layout.
      layout = pya.Application.instance().main_window().current_view().active_cellview().layout() 
      if layout == None:
        raise Exception("No layout")
    
      cellview = pya.Application.instance().main_window().current_view().active_cellview()
    
      # find the currently selected cell:
      topcell = pya.Application.instance().main_window().current_view().active_cellview().cell
      if topcell == None:
        raise Exception("No cell")
    
      #to save layer file with specific name
      layerFile = topcell.name
    
    def addRow(self):
      config()
      numRows = dialog.tW.rowCount
      dialog.tW.insertRow(numRows)
      dialog.tW.setItem(numRows,0,QTableWidgetItem(str("tmp")))
      dialog.tW.setItem(numRows,1,QTableWidgetItem(str(999)))
      dialog.tW.setItem(numRows,2,QTableWidgetItem(str(0)))
    
    
    def readLayer(): 
      config()
      dialog.tech.text=layerFile
      Liter = lv.begin_layers()
      while not Liter.at_end():
        lp = Liter.current()
        if(lp.layer_index()>= 0 ):
            info = layout.get_info(lp.layer_index())
            #print('Selected Layer:', info.name, info.layer, info.datatype)
            numRows = dialog.tW.rowCount
            dialog.tW.insertRow(numRows)
            #dialog.tW.setItem(1,1,QTableWidgetItem("toto"))
            dialog.tW.setItem(numRows,0,QTableWidgetItem(str(info.name)))
            dialog.tW.setItem(numRows,1,QTableWidgetItem(str(info.layer)))
            dialog.tW.setItem(numRows,2,QTableWidgetItem(str(info.datatype)))
        else:
            numRows = dialog.tW.rowCount
            dialog.tW.insertRow(numRows)
    
            dialog.tW.setItem(numRows,0,QTableWidgetItem(str(lp.source_name)))
            dialog.tW.setItem(numRows,1,QTableWidgetItem(str(lp.source_layer)))
            dialog.tW.setItem(numRows,2,QTableWidgetItem(str(lp.source_datatype)))
        Liter.next()
    
    
    def saveLyp(self):
           dialog.deleteLater()
           config()
           numRows = dialog.tW.rowCount
           for nr in range (0,numRows):
             layerName = dialog.tW.item(nr,0).text
             layerNo   = int(dialog.tW.item(nr,1).text)
             layerD    = int(dialog.tW.item(nr,2).text)
             changeLay(layerName,layerNo,layerD)
           layerFile=dialog.tech.text
           lv.add_missing_layers()         
           lv.save_layer_props(layerFile+".lyp")
           lv.load_layer_props(layerFile+".lyp")
           v=pya.MessageBox.info("INFO", "Layer updated and wrote "+layerFile+".lyp file", pya.MessageBox.Ok)
    
    def changeLay(layerName,layerNo,layerD):
             config()
             # rename the layer in the layout itself to match the layer assistant
             if layerD > 0:   # here we check if the datatype has been changed
               oldLayerD=0
               oldLayerIndex=layout.find_layer(layerNo,oldLayerD)
               oldInfo = layout.get_info(oldLayerIndex)
               oldD = oldInfo.datatype
               layer_index = layout.layer(layerNo,oldD)  # assume that old dt is 0 - use old layer_index to update
             else:  
               layer_index = layout.layer(layerNo,layerD) # dataype not changed - use new==old datatype 0
             info = layout.get_info(layer_index)
             info.name = layerName
             info.layer = layerNo
             info.datatype = layerD
             layout.set_info(layer_index, info)
    
             # rename the layer in the layer assistant
             cellview_index = pya.LayoutView.current().active_cellview_index()
             layer_index = layout.layer(layerNo, layerD)
             Liter = lv.begin_layers()
             while not Liter.at_end():
              checkLayerIndex=layout.find_layer(layerNo,layerD)
              if checkLayerIndex != None:
                if Liter.current().source_layer == layerNo:
                    lp = Liter.current()
                    lp.source_name = layerName
                    lp.source_layer = layerNo
                    lp.source_datatype = layerD
                    pya.LayoutView.current().replace_layer_node(Liter, lp)
              else:
                    infoNew = pya.LayerInfo.new(layerNo,layerD)
                    infoNew.name=layerName
                    infoNew.layer=layerNo
                    infoNew.datatype=layerD
                    layer_idNew=layout.insert_layer(infoNew)
    
                    lnew = pya.LayerPropertiesNode().new
                    print(lnew)
                    lnew.source_layer_index = layer_idNew
                    lnew.source_name=layerName
                    lnew.layer=layerNo
                    lnew.datatype=layerD
                    pya.LayoutView.current().insert_layer( lv.end_layers(), lnew )
              Liter.next()
    
    def downL(self):
        numRows = dialog.tW.rowCount
        numCol = dialog.tW.columnCount
        row=dialog.tW.currentRow()
        column = dialog.tW.currentColumn()
        if row < numRows-1:
             dialog.tW.insertRow(row+2)
             for i in range(numCol):
                   dialog.tW.setItem(row+2,i,dialog.tW.takeItem(row,i))
                   dialog.tW.setCurrentCell(row+2,column)
             dialog.tW.removeRow(row)        
    
    
    def upL(self):
        numRows = dialog.tW.rowCount
        numCol = dialog.tW.columnCount
        row=dialog.tW.currentRow()
        column = dialog.tW.currentColumn()
    
        if row > 0:
           dialog.tW.insertRow(row-1)
           for i in range(numCol):
                 dialog.tW.setItem(row-1,i,dialog.tW.takeItem(row+1,i))
                 dialog.tW.setCurrentCell(row-1,column)
           dialog.tW.removeRow(row+1)         
    
    
    def bexit(self):
      dialog.deleteLater()
    # do nothing ...
    
    
    dialog = QDialog(pya.Application.instance().main_window())
    dialog.windowTitle = "Generate PolygonBox"
    layout = QVBoxLayout.new(dialog)
    dialog.setLayout(layout)
    
    # read the GUI from qt designer
    ui_path = join("./klayoutLib/pymacros", "layer.ui") 
    ui_file = pya.QFile(ui_path)
    
    parent = pya.Application.instance().main_window()
    ui_file.open(pya.QIODevice.ReadOnly)
    dialog = pya.QFormBuilder().load(ui_file, parent)
    ui_file.close()
    readLayer()
    
    dialog.quit.clicked(bexit)
    dialog.add.clicked(addRow)
    dialog.updateL.clicked(saveLyp)
    #dialog.up.clicked(upL)
    #dialog.down.clicked(downL)
    
    dialog.show()
    
  • edited March 2018

    Nice idea :-)

    Actually layer sources and the layer views are much more powerful, so I don't think you can capture the full beauty in a single table (i.e. hierarchies, transformations, property selectors, tabs etc.). But for certain applications that's surely sufficient.

    The applications I know usually produce .lyp files from some tech database or technology description files for the original source. That can also be scripted.

    Regards,

    Matthias

Sign In or Register to comment.