It looks like you're new here. If you want to get involved, click one of these buttons!
Hello,
I'm attempting to create a plugin (in Klayout 0.30.5) that loads a second layout if some conditions are triggered, and want to be able to use the plugin there. I'm having a bit of trouble understanding the structure of plugins and when the mouse_button_pressed_event etc. are actually called.
Here's the relevant skeleton of my code:
# $description: test
# $show-in-menu
# $menu-path: tools_menu>end("Test").end
import pya as kl
class PluginTestFactory(kl.PluginFactory):
def __init__(self):
self.add_submenu("menu_name", "inset_pos", "title")
self.register(29318, "plugin_name", "test_plugin")
def create_plugin(self, manager, dispatcher, view):
return PluginTest(view)
class PluginTest(kl.Plugin):
def __init__(self,view):
self.curr_annot = kl.Annotation()
self.curr_annot.p1 = kl.DPoint(0,0)
self.curr_annot.p2 = kl.DPoint(0,0)
self.curr_annot.fmt = ""
self.curr_annot.fmt_x = ""
self.curr_annot.fmt_y = ""
self.curr_annot.outline = self.curr_annot.OutlineBox
self.curr_annot.style = self.curr_annot.StyleLine
view.insert_annotation(self.curr_annot)
def mouse_button_pressed_event(self, p, buttons, prio):
print("hello")
def mouse_button_released_event(self, p, buttons, prio):
self.match()
def mouse_moved_event(self, p, buttons, prio):
self.curr_annot.p2 = p
def match(self):
big_menu = kl.QDialog()
big_menu.layout = kl.QGridLayout()
containing_layout = kl.QWidget()
self.layoutwidg = kl.LayoutViewWidget(containing_layout)
cv = self.layoutwidg.view().create_layout(True)
viewing_layout = self.layoutwidg.view().cellview(cv).layout()
big_menu.layout.addWidget(self.layoutwidg,0,0,1,1)
big_menu.show()
if __name__ == "__main__":
PluginTestFactory()
When I click on the Tools>test menu button, a "test_plugin" button appears on the toolbar. The annotation appears and follows my mouse around before pressing the test_plugin button; I expected the annotation to appear, but the fact that it follows my mouse around implies that the mouse_moved_event is being called implicitly.
When I click the button in the toolbar, the "Basic Editing" pane pops up (why does that happen, by the way? It's annoying.), but no other effects occur; clicking and dragging and releasing does nothing. But when I open the debugger, I can put a breakpoint on the mouse_button_pressed_event and the mouse_button_released_event lines and it stops at both of them. If I step past the self.match() call, nothing else happens.
But if I step into the self.match() call and let it run, it opens up the QDialog I asked for. Within this QDialog, it appears that the mouse_button_pressed_event is completely inactive, whereas the mouse_button_released_event and mouse_moved_event calls are still active (in the sense that it stops at a breakpoint in the mouse_button_released_event function).
This is all very confusing to me, and I would like to understand what's going on. Is there some sort of infinite recursion being headed off by avoiding the self.match() call when the debugger breakpoint is absent, and is that why it isn't run?
The simplest question that would move me forward is: How do I force the mouse_button_pressed_event to be recognized in the layout in this pop-up window?
Thanks so much!
Noah
Comments
Hi Noah,
did you check the documentation?
https://www.klayout.de/doc-qt5/programming/application_api.html#k_11 explains the concept of the mouse events. Specifically it says:
Here is more example code: https://www.klayout.de/doc-qt5/code/class_PluginFactory.html
There are packages implementing Plugins, for example this one: https://github.com/s910324/SplitShapePlugin. You can study that one for example. It is well made.
Matthias
Thanks for your reply! My two questions are:
1. It says in the documentation that
However, when I open this new LayoutView in the pop-up window, there is no tool bar button to press, so the plugin never gets activated (and the Select tool appears to always be activated). If I re-click on the button in the main window, it doesn't seem to activate the plugin in the pop-up window. And if I manually call
self.activated, nothing seems to happen. So I'm asking how to activate the plugin, either manually or through code, in this new LayoutView.2. It seems that in this case, the other mouse events are working as intended, but I cannot seem to get
mouse_button_pressed_eventto be called withprio=False. I saw at this link that there had been trouble in the past with mouse_button_pressed_event not working perfectly, so I'm concerned there might be a bug in its implementation, even though that link says it's been fixed.I am sorry because these seem like basic questions, but it feels like what I'm seeing is counter to the documentation. Thanks so much for your help!
(P.S. I'm sorry I posted this in the Verification category; I could not figure out how to either delete the topic or change the category after it was posted.)
Noah
So then let's start with a minimum example:
If I run this example, I get a new button in the tool bar, named "test_plugin". That is the name, the plugin got in the "register" call (third parameter).
While that function is not active, I receive calls to "mouse_button_moved" with prio = False. These are the background events that are sent to the plugin with low priority and because no other plugin claims them. If I activate the function by pressing the "test_plugin" function, I receive these events with prio = True. Unlike other plugins, mine claims these events by returning True from the "mouse_moved_event" callback. Because of these, these events are not available to other plugins and this is why for example the cursor position display freezes when the plugin is activated. Usually it's best not to claim the events and to return False.
The same is true, when you click at one point - in that case, "mouse_click_event" calls are issued.
Now to the "mouse_button_pressed_event" and "mouse_button_released_event": unlike Qt events for example, these events get issued only alternatively to the click event. A click event is issued, when you press the mouse and release the button on the same location. If you move the mouse in between pressing and releasing (a drag operation), you will receive a mouse button press event, some move events and then a mouse button release event. Since the application can't know what is going to happen, the mouse button press event is delayed into the first move operation.
That concept is basis for all mouse-driven features inside KLayout and supports "click-move-click" (pick and place) and "press-move-release" (drag) scenarios. But you cannot get an immediate event on mouse button press, if that is what you are asking for.
Matthias
Hello Matthias,
Again, thanks for your response and your helpful code. Can you verify the following for me in this plugin?
If this is the case, I think there is a bug that might need attending to.
No, that is not how it is intended.
When the "test_plugin" is not activated, there is no mouse_click_event with prio=False because the active plugin (Select) claims that event.
When the "test_plugin" is not activated, there is a mouse_button_pressed_event with prio=False, but only after you moved the mouse a little, so that it is considered a drag operation. The active plugin (Select) is not claiming that event, so it is delivered to the test plugin with prio=False. Pressing the button, moving the mouse, and releasing the button gives a sequence of events: mouse_button_pressed_event, mouse_moved_event (n times), mouse_button_released_event, all with prio=False.
When the "test_plugin" is activated, when clicking a button, you receive a mouse_click_event with prio=True. When pressing the button and moving the mouse, you get a mouse_button_pressed_event, then mouse_moved_events and finally a mouse_button_released_event with prio=True, but only after you moved the mouse a little, so the events can be distinguished from a single click.
Matthias
Hello Matthias,
I'm so sorry, I see what's happening now. So after running the script but before clicking the plugin button, Select is not claiming any of _clicked, _pressed, _released or _moved. But after clicking the plugin button and then re-clicking Select, it claims _clicked and _pressed, but still not _released or _moved. Is this correct? And that's why it's printing _released and _moved? Interesting that it doesn't claim _released.