Button Shortcut to PCell?

NMFNMF
edited February 2015 in Ruby Scripting
I've found elsewhere how to add a button to the toolbar (http://klayout.de/forum/comments.php?DiscussionID=361) and I've made a number of PCells that are useful to me, personally. I'm wondering if there is an easy way to make a button that acts as a shortcut to a specific PCell? It basically would save the time of clicking on "Instance", selecting the library, and then selecting the PCell. I don't want to automatically add the PCell without user input, so ideally clicking the button would ask for the parameters. I'm not sure which is the best route (if either would work):
1) Figure out a keyboard shortcut to the PCell window
2) Create a script that prompts for the parameters and then calls the PCell
Does that make any sense?
Thanks!

Comments

  • edited February 2015

    I think #1 may be possible but difficult.

    Just go with #2. For that you need to:

    1. Know what PCell parameters you will want to pass. There is a script here that will spit that out for any PCell.
    2. Make a dialog box. There are two ways: Create .ui file in Qt Creator and call it in a script (instructions, scroll to "Using the designer"), or hard-code the functions in a self-contained script (example).
    3. Using the above, place the PCell on the layout. (Example)

    (Shameless plug: Make sure to share your script on the hopefully upcoming community script sharing site when it is complete! :-)

  • NMFNMF
    edited 2:19AM
    Thanks! I'll see what I can do tomorrow. A community site would be awesome- all I really had to start with was the sample P-Cell of "how to make a circle" and have been building up from there. Even a few more examples would be really helpful to someone starting with PCells for the first time.
  • NMFNMF
    edited February 2015

    OK, I think I made pretty good progress based on the links you posted, and some other things I found on the forums (and a detour through Qt tutorials that didn't help much).

    If I run this script in the IDE I get the button on the toolbar that I want. When I click it the user is prompted for the parameters I know I need, and then I pass them to the script to create the PCell, but I get this error:

    "Object cannot be copied here in layout::add_pcell_variant in Action::triggered"

    I'm guessing the code calling the PCell is in the wrong area of the script?

    Also, how can I get the macro to run at startup so the button is on the tool bar to begin with? I got another error there.

    Many thanks!

    module PhotonicsButtons
    
        include RBA
    
            $rect_grate = MenuAction.new( "Rectangluar Grating", "" ) do 
    
            app = RBA::Application.instance
            mw = app.main_window
    
            dialog = QDialog.new(Application.instance.main_window)
            dialog.windowTitle = "Input Rectangular Grating Parameters"
    
            formlayout = QVBoxLayout::new(dialog)
            dialog.setLayout(formlayout)
    
            # variable text input :
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Waveguide Layer"
            l = QLineEdit.new(dialog)
            formlayout.addWidget(l)
            l.text = "9/727"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Width of Grating"
            w = QLineEdit.new(dialog)
            formlayout.addWidget(w)
            w.text = "1"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Height of Grating"
            h = QLineEdit.new(dialog)
            formlayout.addWidget(h)
            h.text = "10"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Number of Gratings"
            n = QLineEdit.new(dialog)
            formlayout.addWidget(n)
            n.text = "10"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Spacing of Gratings"
            s = QLineEdit.new(dialog)
            formlayout.addWidget(s)
            s.text = "1"
    
            # separation line
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "\n"
    
            # OK button
            buttonOK = QPushButton.new(dialog)
            formlayout.addWidget(buttonOK)
            buttonOK.text = " OK "
            buttonOK.clicked do 
                    dialog.accept()
            end
    
            dialog.exec
    
    
            cv = RBA::CellView::active
            ly = cv.layout 
            top = cv.cell
    
            # find the lib
            lib = RBA::Library.library_by_name("NMFPhotonics")
            lib || raise("Unknown lib 'NMFPhotonics'")
    
            # find the pcell
            pcell_decl = lib.layout.pcell_declaration("RectGrating")
            pcell_decl || raise("Unknown PCell 'RectGrating'")
    
            # set the parameters
            param = { "l" => l, 
                      "w" => w, 
                      "h" => h,
                      "n" => n,
                      "s" => s }
    
            # build a param array using the param hash as a source
            pv = pcell_decl.get_parameters.collect do |p|
              param[p.name] || p.default
            end
    
            # create a PCell variant cell
            pcell_var = ly.add_pcell_variant(lib, pcell_decl.id, pv)
    
            # instantiate that cell
            t = RBA::Trans::new(RBA::Trans::r90, 0, 0)
            pcell_inst = ly.cell(top).insert(RBA::CellInstArray::new(pcell_var, t))
    
            # write the output
            # ly.write("pcells.gds")
    
        end
    
    
        menu = RBA::Application.instance.main_window.menu
        menu.insert_separator("@toolbar.end", "name")
        menu.insert_item("@toolbar.end", "rect_grate", $rect_grate)
    end
    
  • edited February 2015

    Hi NMF,

    I'm impressed :-)

    To be frank, I can't reproduce the problem you had with "Object cannot be copied here in layout::add_pcell_variant in Action::triggered". I don't have your PCell code but I think it's related to that code. Maybe you can try to use the debugger to locate the problem.

    I found a tiny bug in the script: the line

        pcell_inst = ly.cell(top).insert(RBA::CellInstArray::new(pcell_var, t))
    

    should be

        pcell_inst = top.insert(RBA::CellInstArray::new(pcell_var, t))
    

    Using the Basic.CIRCLE PCell works for me with that patch.

    You can configure to run the macro at startup using the "Macro properties" dialog: to open the dialog use the properties tool button above the macro text left to the "wrench" icon. Check "Run on startup". Please be aware that your macro needs "MenuAction" which appears to be defined somewhere else. If you have that class in another file, make sure this file is executed as startup too, preferably with "Run early on startup" so it's executed before your main macro, or load this file through "require".

    Matthias

  • NMFNMF
    edited 2:19AM

    Matthias - you're too kind! If I have coded further it is by standing on the shoulders of giants.

    Fixed the bug but still get the same error- debug pointed to another script I had installed (density_map.lym) Removed that and I get a new error:

    uninitialized constant PhotonicsButtons::MenuAction

    Which I guess is what you were talking about. I don't have that class defined anywhere, and found the following in the forums and inserted it:

    module PhotonicsButtons
    
    include RBA
    
    class MenuAction < Action
        def initialize( title, shortcut, &action ) 
        self.title = title
        self.shortcut = shortcut
        @action = action
    end
    def triggered 
        @action.call( self ) 
    end
    private
        @action
    end
    
    $rect_grate = MenuAction.new( "Rectangluar Grating", "" ) do 
    ...
    

    But I still get an error at the same line...
    I guess I can only copy and paste together so much!

  • edited 2:19AM

    Can you post your PCell code too? Then I can reproduce your error or fix the code.

    I don't have time right now to try, but it's possible just replacing the word "MenuAction" with "Action" may work. (And remove the class MenuAction you pasted at the top).

    Also, as a general statement, the whole MenuAction.new(...) do ... end part, and the last three lines, are perhaps not the best way to do it in my opinion. I know you copied from another example so it's not your fault. But in general you can leave off any menu manipulation whatsoever from your code and just use the Properties button that Matthias talked about. Set "Show in menu" to true, set Menu Path to "@toolbar.end" (without the quotes), click OK. (Make sure you use .lym file though, which supports this with nothing required to be typed in the script itself).

    Anyway, post your PCell code and I will help get it working.

    Thanks,
    David

  • NMFNMF
    edited 2:19AM

    I'll give that a try in a few minutes. Below is the PCell code:

    module NMFPhotonics
    
        include RBA
    
        # Remove any definition of our classes (this helps when 
        # reexecuting this code after a change has been applied)
        NMFPhotonics.constants.member?(:RectGrating) && remove_const(:RectGrating)
        NMFPhotonics.constants.member?(:NMFPhotonics) && remove_const(:NMFPhotonics)
    
        # This PCell creates simple rectangular gratings
        class RectGrating < PCellDeclarationHelper
    
            include RBA
    
            def initialize
    
            # Important: initialize the super class
            super
    
            # declare the parameters            
            param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
            param(:w, TypeDouble, "Width of Grating", :default => 1.0)
            param(:h, TypeDouble, "Height of Grating", :default => 10.0)
            param(:n, TypeInt, "Number of Gratings", :default => 10)
            param(:s, TypeDouble, "Space between first and second Grating", :default => 1.0)
        end
    
        def display_text_impl
            # Provide a descriptive text for the cell
            "RectGrating(n=#{n.to_s},w=#{w.to_s},h=#{h.to_s},s=#{s.to_s})"
        end
    
    
        def can_create_from_shape_impl
            # Implement the "Create PCell from shape" protocol: we can use any shape which 
            # has a finite bounding box
            shape.is_box? || shape.is_polygon? || shape.is_path?    
        end
    
        def parameters_from_shape_impl
            # Implement the "Create PCell from shape" protocol: we set r and l from the shape's 
            # bounding box width and layer.
            set_r shape.bbox.width * layout.dbu / 2
            set_l layout.get_info(layer)
        end
    
        def transformation_from_shape_impl
            # Implement the "Create PCell from shape" protocol: we use the center of the shape's
            # bounding box to determine the transformation
            Trans.new(shape.bbox.center)
        end
    
        def produce_impl
    
            # This is the main part of the implementation: create the layout
    
            # fetch the parameters
            w_dbu = w / layout.dbu
            h_dbu = h / layout.dbu
            s_dbu = s / layout.dbu
    
            n.times do |i|
                # create the shape
                cell.shapes(l_layer).insert(Box.new(i*(w_dbu+s_dbu),0,i*(w_dbu+s_dbu)+w_dbu,h_dbu))
            end
        end
    end
    
    
    
    
    
    
    # Add additional PCells here
    
    # The library where we will put the PCell into     
        class NMFPhotonics < Library
    
            def initialize  
    
                # Set the description
                self.description = "Library of Photonics Devices"
    
                # Create the PCell declarations
                layout.register_pcell("RectGrating", RectGrating::new)
                # That would be the place to put in more PCells ...
    
                # Register us with the name "MyLib".
                # If a library with that name already existed, it will be replaced then.
                register("NMFPhotonics")
    
            end
    
        end
    
    # Instantiate and register the library
    NMFPhotonics::new
    
    end
    
  • NMFNMF
    edited 2:19AM

    OK, I did some more reading and I see that the code wrapper I was using was from old scripts before macros. (From http://klayout.de/forum/comments.php?DiscussionID=310&Focus=1425#Comment_1425). Right now I have:

    module PhotonicsButtons
    
        $rect_grate = Action.new() do 
    
            include RBA
    
    
            app = RBA::Application.instance
            mw = app.main_window
    
            dialog = QDialog.new(Application.instance.main_window)
            dialog.windowTitle = "Input Rectangular Grating Parameters"
    
            formlayout = QVBoxLayout::new(dialog)
            dialog.setLayout(formlayout)
    
            # variable text input :
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Waveguide Layer"
            l = QLineEdit.new(dialog)
            formlayout.addWidget(l)
            l.text = "9/727"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Width of Grating"
            w = QLineEdit.new(dialog)
            formlayout.addWidget(w)
            w.text = "1"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Height of Grating"
            h = QLineEdit.new(dialog)
            formlayout.addWidget(h)
            h.text = "10"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Number of Gratings"
            n = QLineEdit.new(dialog)
            formlayout.addWidget(n)
            n.text = "10"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Spacing of Gratings"
            s = QLineEdit.new(dialog)
            formlayout.addWidget(s)
            s.text = "1"
    
    
    
    
    
    
            # separation line
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "\n"
    
            # OK button
            buttonOK = QPushButton.new(dialog)
            formlayout.addWidget(buttonOK)
            buttonOK.text = " OK "
            buttonOK.clicked do         
                dialog.accept()
            end
    
            dialog.exec
    
    
            cv = RBA::CellView::active
            ly = cv.layout     
            top = cv.cell
    
            # find the lib
            lib = RBA::Library.library_by_name("NMFPhotonics")
            lib || raise("Unknown lib 'NMFPhotonics'")
    
            # find the pcell
            pcell_decl = lib.layout.pcell_declaration("RectGrating")
            pcell_decl || raise("Unknown PCell 'RectGrating'")
    
            # set the parameters
            param = { "l" => l, "w" => w, "h" => h, "n" => n, "s" => s }
    
            # build a param array using the param hash as a source
            pv = pcell_decl.get_parameters.collect do |p|
                param[p.name] || p.default
            end
    
            # create a PCell variant cell
            pcell_var = ly.add_pcell_variant(lib, pcell_decl.id, pv)
    
            # instantiate that cell
            t = RBA::Trans::new(RBA::Trans::r90, 0, 0)
            pcell_inst = top.insert(RBA::CellInstArray::new(pcell_var, t))
    
        end
    end
    

    But now the button doesn't do anything. If I remove:

    $rect_grate = Action.new() do 
    ...
    end
    

    It will run when I hit the play button in the IDE but I still get the original error message pointing to the line:

    pcell_var = ly.add_pcell_variant(lib, pcell_decl.id, pv)
    
  • edited 2:19AM

    Yes, the only down-side of .lym is you can't call one .lym from another .lym using the ruby "load" command. (You can call .rb files though.) Otherwise, .lym and its associated benefits (like "Show in menu") is preferred.

    BTW Matthias, is that an option for a future release? (Adding the ability to 'load' one lym from another.)

    Thanks for posting the PCell. I can't try it right now but will in a few hours and let you know what the issue is.

  • edited February 2015

    You were very close!

    Search for the string "#DNH" to see what I added. Basically,

    1. You needed to convert the string "9/727" into an integer layer number 9 and an integer datatype 727.
    2. You needed to convert w, h, n, and s, from their types (They were of type QLineEdit) into float or int as appropriate. For this, first get the text value using .text and then convert to float or int using .to_f or .to_i. Note that the way I discovered this is I added the line "print w.class" above where param was defined. This prints out the class of w, which was QLineEdit not String, so I knew I had to call the .text function first.
    3. At the end you need lv.add_missing_layers, which adds layer 9/727 if it doesn't already exist. Otherwise you won't see anything.

    Here is the PCell, and then I'll paste the calling .lym file afterwards.

    module NMFPhotonics
    
        include RBA
    
        # Remove any definition of our classes (this helps when 
        # reexecuting this code after a change has been applied)
        NMFPhotonics.constants.member?(:RectGrating) && remove_const(:RectGrating)
        NMFPhotonics.constants.member?(:NMFPhotonics) && remove_const(:NMFPhotonics)
    
        # This PCell creates simple rectangular gratings
        class RectGrating < PCellDeclarationHelper
    
            include RBA
    
            def initialize
    
            # Important: initialize the super class
            super
    
            # declare the parameters            
            param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
            param(:w, TypeDouble, "Width of Grating", :default => 1.0)
            param(:h, TypeDouble, "Height of Grating", :default => 10.0)
            param(:n, TypeInt, "Number of Gratings", :default => 10)
            param(:s, TypeDouble, "Space between first and second Grating", :default => 1.0)
        end
    
        def display_text_impl
            # Provide a descriptive text for the cell
            "RectGrating(n=#{n},w=#{w},h=#{h},s=#{s})" #DNH MODIFIED -- you don't need .to_s
        end
    
    
        def can_create_from_shape_impl
            # Implement the "Create PCell from shape" protocol: we can use any shape which 
            # has a finite bounding box
            shape.is_box? || shape.is_polygon? || shape.is_path?    
        end
    
        def parameters_from_shape_impl
            # Implement the "Create PCell from shape" protocol: we set r and l from the shape's 
            # bounding box width and layer.
            set_r shape.bbox.width * layout.dbu / 2
            set_l layout.get_info(layer)
        end
    
        def transformation_from_shape_impl
            # Implement the "Create PCell from shape" protocol: we use the center of the shape's
            # bounding box to determine the transformation
            Trans.new(shape.bbox.center)
        end
    
        def produce_impl
    
            # This is the main part of the implementation: create the layout
    
            # fetch the parameters
            w_dbu = w / layout.dbu
            h_dbu = h / layout.dbu
            s_dbu = s / layout.dbu
    
            n.times do |i| # DNH ADDED THE .to_i METHOD. For some reason, n is turning out to be a float here
                # create the shape
                cell.shapes(l_layer).insert(Box.new(i*(w_dbu+s_dbu),0,i*(w_dbu+s_dbu)+w_dbu,h_dbu))
            end
        end
    end
    
    
    
    
    
    
    # Add additional PCells here
    
    # The library where we will put the PCell into     
        class NMFPhotonics < Library
    
            def initialize  
    
                # Set the description
                self.description = "Library of Photonics Devices"
    
                # Create the PCell declarations
                layout.register_pcell("RectGrating", RectGrating::new)
                # That would be the place to put in more PCells ...
    
                # Register us with the name "MyLib".
                # If a library with that name already existed, it will be replaced then.
                register("NMFPhotonics")
    
            end
    
        end
    
    # Instantiate and register the library
    NMFPhotonics::new
    
    end
    

    Here is the calling .lym file:

    module PhotonicsButtons
    
    #    $rect_grate = Action.new() do  #DNH REMOVED
    
            include RBA
    
    
            app = RBA::Application.instance
            mw = app.main_window
    
            dialog = QDialog.new(Application.instance.main_window)
            dialog.windowTitle = "Input Rectangular Grating Parameters"
    
            formlayout = QVBoxLayout::new(dialog)
            dialog.setLayout(formlayout)
    
            # variable text input :
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Waveguide Layer"
            l = QLineEdit.new(dialog)
            formlayout.addWidget(l)
            l.text = "9/727"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Width of Grating"
            w = QLineEdit.new(dialog)
            formlayout.addWidget(w)
            w.text = "1"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Height of Grating"
            h = QLineEdit.new(dialog)
            formlayout.addWidget(h)
            h.text = "10"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Number of Gratings"
            n = QLineEdit.new(dialog)
            formlayout.addWidget(n)
            n.text = "10"
    
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "Spacing of Gratings"
            s = QLineEdit.new(dialog)
            formlayout.addWidget(s)
            s.text = "1"
    
    
    
    
    
    
            # separation line
            label = QLabel.new(dialog)
            formlayout.addWidget(label)
            label.text = "\n"
    
            # OK button
            buttonOK = QPushButton.new(dialog)
            formlayout.addWidget(buttonOK)
            buttonOK.text = " OK "
            buttonOK.clicked do         
                dialog.accept()
            end
    
            dialog.exec
    
    
            lv = mw.current_view #DNH ADDED. The layout view. Need this for the add_missing_layers method later
            cv = RBA::CellView::active
            ly = cv.layout     
            top = cv.cell
    
            # find the lib
            lib = RBA::Library.library_by_name("NMFPhotonics")
            lib || raise("Unknown lib 'NMFPhotonics'")
    
            # find the pcell
            pcell_decl = lib.layout.pcell_declaration("RectGrating")
            pcell_decl || raise("Unknown PCell 'RectGrating'")
    
            # set the parameters #DNH MODIFIED
      lay_num, dt_num = l.text.split('/').map { |s| s.to_i } # Layer number, datatype number
      p w.class
      param = { 
        "l" => LayerInfo.new(lay_num,dt_num), 
        "w" => w.text.to_f, 
        "h" => h.text.to_f, 
        "n" => n.text.to_i, 
        "s" => s.text.to_f 
      }
    
            # build a param array using the param hash as a source
            pv = pcell_decl.get_parameters.collect do |p|
                param[p.name] || p.default
            end
    
            # create a PCell variant cell
            pcell_var = ly.add_pcell_variant(lib, pcell_decl.id, pv)
    
            # instantiate that cell
            t = RBA::Trans::new(RBA::Trans::r90, 0, 0)
            pcell_inst = top.insert(RBA::CellInstArray::new(pcell_var, t))
    
            lv.add_missing_layers #DNH ADDED
    
    #    end #DNH REMOVED
    end
    
  • edited 2:19AM

    Lastly, you could put some error checking on the input values, and also I'd recommend wrapping the bulk of the calling .lym file in

    lv.transaction("Generate rect grating")
    begin
      # CODE HERE
    ensure 
      lv.cancel
      lv.commit
    end
    

    Incidentally, I use KL for photonics too. Glad to see another photonics user on the forum. :)

  • NMFNMF
    edited 2:19AM

    Outstanding! Got it working, thank you!

    Next step question: the script drops the PCell at 0,0. Is it possible for the user to place the PCell with the mouse (same as when you insert an instance?) I remember reading it is non-trivial for scripts to interact with mouse clicks. I guess I could add those as inputs as well (user defined x and y). Or maybe make it so the PCell is dropped in the center of the screen?

    And small world! I found your "TheRedToolbox" which is more or less what I'm trying to create. I want to add a few PCell buttons to the toolbar for repetitive structures we want to vary on the wafer. Then, package it up so my co-workers could use it as well. Spending a week (so far) now learning PCells and scripting will save us a ton of time in layout.

  • edited February 2015

    You are right, it's nontrivial. I wanted to do that once and gave up (though, I didn't spend a huge amount of time on it).

    If you get it working, post it here so I can see how it works.

    I'd add x and y as user inputs.

    Where did you find TheRedToolbox? It's likely it's a very old and buggy version -- email me on david.n.hutch att gmail and we can discuss more.

  • edited February 2015

    Hi all,

    I really like what is going on here :-)

    I have a suggestion how to enter the instance. Instead of creating the instance at 0,0 you can configure the editor with the requested parameters and enter Instance mode. This code will do this configuration (for Basic.CIRCLE) and enters instance mode:

    app = RBA::Application::instance
    
    # Configure the editor
    app.set_config("edit-inst-angle", "0")
    app.set_config("edit-inst-mirror", "false")
    app.set_config("edit-inst-scale", "1")
    app.set_config("edit-inst-array", "false")
    
    # We'll take Basic.CIRCLE for example here:
    app.set_config("edit-inst-cell-name", "CIRCLE")
    app.set_config("edit-inst-lib-name", "Basic")
    
    # Set the PCell parameters. The format is "name:value;..."
    # The following shows how to represent a layer too. 
    app.set_config("edit-inst-pcell-parameters", "radius:17.5;layer:[layer:16/0]")
    
    # Enter instance mode
    menu = app.main_window.menu
    menu.action("edit_menu.mode_menu.instance").trigger
    

    After the last statement, the mouse drags the instance you have configured and you can drop it. A slightly ugly side effect is that the property window will open too, but you can close it with Ok.

    Implementing a mouse drop scheme directly in Ruby is possible but that involves creating a "Plugin" which adds some other level of complexity here. In the end that solution is capable of integrating rich functionality into the KLayout framework (as a matter of fact, the editor functions are based on the same interface), but if the above scheme is sufficient that is by far the easiest solution.

    Matthias

  • NMFNMF
    edited 2:19AM

    Thanks Matthias, I'll take a crack at that tomorrow.

    Sending email now David.

  • NMFNMF
    edited 2:19AM

    Ah ha, I see now. This is what I meant when I originally posted "Figure out a keyboard shortcut to the PCell window". I kind of like using the built in PCell/Instance window instead of reinventing the wheel with my own input window. Here, the PCell/Instance window works as the input form and the user can place the instance with the mouse.

    Related:
    Is it possible to make the PCell tab active? I assume it must have an attribute associated with it since the window remember which tab I had selected.

  • edited 2:19AM

    Matthias,

    That's really neat, I had no idea you could do that.

    Is it possible to employ a similar trick to draw a shape? Say I wanted to recreate the "Box" button that is already on the toolbar. (I know it exists already, but I'm imagining adding to it some complicated functionality such as programmatically choosing the layer based on what is nearby.) Is the only way to achieve this through Plugins, or is there a way similar to your app.set_config lines above?

    Thanks,
    David

  • edited February 2015

    Well, sorry for mentioning this simple solution so late .. the "action...trigger" trick is basically just simulating the button click on the "Instance" button. No more and no less. That gives no control over what is happening afterwards.

    The wish to select the PCell page is such a case. Unless KLayout selects the PCell page by itself there are only crude hacks to select the PCell page: one solution would involve locating the child widgets in the instance dialog using the Qt binding inside Ruby and directly manipulating them. But that solution will be invalid as soon as tiny things change on the user interface - such as widget names. So that will be a solution which might require a lot of maintenance to keep track of KLayout updates.

    The other solution is the big Plugin one. If you're interested in that: there is a brief description here: http://klayout.de/doc/programming/application_api.html#h2-783. The box functionality can be reimplementation using that scheme, but I don't have sample code at hand.

    I don't dare to recommend any of these solutions. Both are not straightforward to use. You got pretty far with your custom user interface solution already.

    Best regards

    Matthias

  • NMFNMF
    edited 2:19AM

    That makes sense- its such a minor issue I'm not worried about it.

    Slightly bigger question: how can you assign icon's to menu items this way? I've Matthias post the code below:

    a = RBA::Action.new
    a.title = "Push Me!"
    # more, i.e.
    # a.icon = "file path"
    a.on_triggered do
      # put your code here ...
      puts "I was pushed!"
    end
    
    # install the action at the right end of the toolbar with a separator
    menu = RBA::Application.instance.main_window.menu
    menu.insert_separator("@toolbar.end", "name")
    menu.insert_item("@toolbar.end", "my_action", a)
    

    But if you add it to the menu bar through the IDE I haven't been able to figure out how to assign an icon. Is that not possible with this shortcut?

  • edited February 2015

    You can use the a.icon = "file path" line which you commented out?

    But I guess you are asking a way to assign this via GUI, for which there is no way that I know of.

    In fact, I think it cannot be possible, because there is no xml tag contained in the .lym file, and all the macro properties window does is add metadata to the .lym file.

    My first reaction was to suggest to add an xml tag to .lym specification. That seems to be some information you would want to store within the .lym script itself... But then, the icon.png (or whatever) file is still a separate file and if you copy the .lym to another location or computer then the link to the .png can break. So, this doesn't make it any more self-contained, which is perhaps the point of .lym over .rb.

    However it is possible to represent an image as a string, inside the .lym file. For small images such as icons this may be a reasonable approach. Though then you start needing to check the image size before conversion to a string, or to scale the image down prior to converting to string, and it starts to become more complicated.

    Anyway just some thoughts...

  • edited 2:19AM

    Hi NMF,

    by "assign icon in IDE" you mean in the macro properties, right?

    Right now you cannot assign an icon that way. That's because the function was intended to create menu entries.

    But that's a nice feature suggestion.

    Matthias

Sign In or Register to comment.