plugin: right-click menu and function behind mouse event under selection mode

Hi, Matthias,

Thank you for providing KLayout and keeping adding feature to it.

I am writing a plugin to use KLayout as a wafermap GUI (typically, used to extract chip ids based on mouse operation on layout and apply specific operation using these selected chipids) and having two questions:
1. How to add pop-up menu when right-clicking the layout view area?
2. The function behind the mouse event (e.g. left click and drag-selection) under selection mode is charming and is there a way to re-use these functions inside a mouse event (with other code) attached to a new plugin?

Best Regards

Comments

  • Hi!

    You could install event handler on LayoutView.on_selection_changed and do some additional processing. Main window menu command may be installed in .lym file and it may enable/disable event handler functionality.

  • Hi, Eugene,

    Thank you for your feedback.

    Since the code is running under Plugin, do you mean to check the status of LayoutView.on_selection_changed after each mouse_button_released_event? is there a better way to install this event?

    I see the example from SiEPIC on installing a menu under main window. It could work as an alternative way while there is some inconvenience since the mouse has to moved up and look for the right menu there.

  • Hi!

    No, you just monitor selection changes in event handler assigned to LayoutView.on_selection_changed, so you don't need to care about low-level mouse events.

    Python code looks like:

    import pya
    
    main_window = pya.Application.instance().main_window()
    current_view = main_window.current_view()
    
    def on_selection_changed(main_window, current_view):
         for selected_object in current_view.each_object_selected():
             do something useful here
    
    current_view.on_selection_changed = \
        lambda __main_window=main_window, __current_view=current_view: \
            on_selection_changed(__main_window, __current_view)
    
  • @tiboy

    The concept of KLayout does not include a right-click context menu. The mouse buttons are reserved for zoom, select and pan/zoom.

    You can basically implement a right-click menu with a plugin, but doing so puts you outside the basic UI concept and you have to implement that yourself based on the Qt features.

    The selection drag box isn't available currently for reuse - if you want to implement such a feature you need to instantiate a marker (https://www.klayout.de/doc-qt5/programming/application_api.html#k_10) which represents the drag box. Upon mouse press you create it, on mouse move you modify it and on mouse release (or when leaving the function) you erase it. This is basically what the selection feature does as well.

    Matthias

  • Here is some code for a plugin that drags a box:

    # Register this macro as "autorun" to enable the plugin
    
    # This is the plugin implementation
    
    class DragBoxPlugin(pya.Plugin):
    
      def __init__(self, view):
        super(DragBoxPlugin, self).__init__()
        self.marker = None
        self.box = None
        self.start_point = None
        self.view = view
    
      def activated(self):
        pya.MainWindow.instance().message("Click on point to start dragging a box", 10000)
    
      def _clear_marker(self):
        if self.marker is not None:
          self.marker._destroy()
          self.marker = None
    
      def _update_marker(self):
        if self.marker is None:
          self.marker = pya.Marker(self.view)
          self.marker.line_style = 2   # short-dashed
          self.marker.vertex_size = 0  # no vertexes
        self.marker.set(self.box)
    
      def deactivated(self):
        self._clear_marker()
        pya.MainWindow.instance().message("", 0)
    
      def mouse_click_event(self, p, buttons, prio):
        if prio:
          if self.marker is None:
            self.box = pya.DBox(p, p)
            self.start_point = p.dup()  # Note dup() which creates a copy we can store
            self._update_marker()
            self.grab_mouse()
            pya.MainWindow.instance().message("Drag the box and click again", 10000)
          else:
            self._clear_marker()
            self.ungrab_mouse()
            self.box_finished(self.box)
          return True
        return False
    
      def box_finished(self, box):
        # TODO: put in your code to do what you like to do with the box
        pya.MainWindow.instance().message("Box finished: " + str(box), 10000)
    
      def mouse_moved_event(self, p, buttons, prio):
        if prio and self.marker is not None:
          self.box = pya.DBox(self.start_point, p)
          self._update_marker()
          return True
        return False
    
    
    # Implement a "plugin factory". 
    # This object is asked to provide a plugin for each view
    
    class DragBoxPluginFactory(pya.PluginFactory):
    
      def __init__(self):
        super(DragBoxPluginFactory, self).__init__()
        self.has_tool_entry = True
        self.register(-1000, "drag_box", "Drag Box")
    
      def create_plugin(self, manager, root, view):
        return DragBoxPlugin(view)
    
      # Keeps the singleton instance
      instance = None
    
    # Create and store the singleton instance
    DragBoxPluginFactory.instance = DragBoxPluginFactory()
    

    Enjoy, Matthias

  • Thank you, Matthias and Eugene. Your reply and code are very helpful.

Sign In or Register to comment.