Observer, callbacks in Python, custom Path tool

edited November 2015 in Ruby Scripting

in Ruby:

observer = RBA::Observer::new
puts observer

returns:

#<RBA::Observer:0x007f86e2c7c430>

Whereas in Python:

observer = pya.Observer.new()
print (observer)
print (pya.Observer.new)

returns:

None
<built-in method new of type object at 0x7f86e55f7f20>

hence the following code fails:

def f():
  print ("triggered")

#observer.on_triggered(f)
observer.on_signal(f)

pya.Application.instance().main_window().current_view().add_selection_changed_observer(observer)  

Caught the following exception: 'NoneType' object has no attribute 'on_signal' (Class exceptions.AttributeError)

Is there a way to get callbacks in Python?

I read through http://klayout.de/doc/code/class_Observer.html and http://www.klayout.de/doc/programming/python.html

To further inquire about what I want to accomplish: is it possible to write my own script version that provides the GUI interface similar to the Path tool? i.e., custom Path tool -- add Waveguide tool -- clicking on points, having a PCell waveguide start drawing itself, ensuring that a minimum distance was travelled before placing a vertex (constraints in routing), snapping, etc.

Actually, I'd be very happy with simply catching two mouse click events, and getting the (x,y) location in the present cellview.

Thank you
Lukas

Comments

  • edited November -1

    Hi Lukas,

    Regarding the first question: the proper way to create an object in Python is using "Class()", i.e.

    observer = pya.Observer()
    

    However, that won't be much help. The Observer pattern is a simple way of attaching events to internal state changes. To utilize it you'll need to reimplement the basic Observer class and override "signal". Here is an example:

    import pya
    
    class MyObserver(pya.Observer):
      def signal(self):
        print("Triggered")
    
    pya.Application.instance().main_window().current_view().add_selection_changed_observer(MyObserver())
    

    The "event" mechanism was added later to simplify and generalize this pattern. An example for an event is the Action's on_triggered event. To bind code to an event, you define a function and use the event method to assign the function:

    def f():
      print("Action triggered")
    
    # create a new Action and attach f to the event
    a = pya.Action()
    a.on_triggered(f)
    
    # emulate a trigger
    a.trigger()
    

    Basically an event is similar to the Observer pattern but it does not require an observer object. Instead the function is bound directly to the observable. This approach is more general since the function can take any number of arguments. On the other hand, you can only bind a single observer function to an event.

    There is more about the Python details here: http://www.klayout.de/doc/programming/python.html.

    Regarding the problem of catching mouse events this is a bit more elaborate. It's possible but you'll need to implement a "Plugin". There is a general introduction about the plugin concept here: http://www.klayout.de/doc/programming/application_api.html#k_11.

    I short, KLayout's architecture is built around modules. There are different modules for various functions: the rulers/annotations are one module, the editing features are another module, the image overlay feature is a separate module and so forth. Basically everything where user interactions are required on the canvas a module is involved. There are some few requirements that a module must fulfil: specifically it has to register within the system, so KLayout can dispatch the mouse events and other requests to specific plugins. Plugins are not always active: usually a plugin registers itself for a specific mode and will only become active then. If a plugin is active, you basically have full control over the mouse events. You can have a plugin tracking mouse events in the other modes as well but for a clean separation of your new mode from other modes, I'd suggest to implement a specific mode and stay inactive when other modes are active.

    There is a small example for a plugin here: http://www.klayout.de/doc/code/class_PluginFactory.html.

    Some details of the plugin concept are not accessible from scripted plugins - for example you cannot implement your own non-layout objects (like rulers or images) within scripted plugins. But I understand your application is to provide special editing functions only.

    Best regards,

    Matthias

Sign In or Register to comment.