Is it possible to auto change Desktops depending on context?

   5318   24   5
User Avatar
Member
654 posts
Joined: Aug. 2014
Offline
I'd like to change Desktops depending on context. For example, if I'm inside a SOP network, I'd like Houdini to automatically switch to Desktop A. If I then dive into a Copernicus network, I'd like it to automatically use Desktop B. If I enter LOPs, let it switch to Desktop C. And so on.
Is this possible?
Edited by ajz3d - Aug. 5, 2024 18:19:07
User Avatar
Member
8177 posts
Joined: Sept. 2011
Offline
no, it's the other way around: you can change context by changing the desktop.
User Avatar
Member
654 posts
Joined: Aug. 2014
Offline
Yes, so I've noticed. I must say I find it annoying when after switching desktops I'm taken someplace else in the network. But that's another pair of shoes.

Anyway, I'm using different desktops for each context, with completely different pane layouts, network viewer settings, network snapping and other stuff. So I wish there was some way of forcing Houdini to automatically switch desktops, even if it involves some reasonable hacking (of hou.pyperhaps?).

If it's really impossible, then what I'd like to be able to do at least, is to create a radial menu with most used desktops, so that I could easily access them when necessary. But, I searched through HOM documentation (particularly the hou.Desktopclass) and I didn't find any methods that would allow us to access saved desktops. So I'm not sure if that's possible either. Most probably not.
User Avatar
Member
247 posts
Joined: May 2017
Offline
Hi, you can try the following aproche:
- Create a shelftool, under edit tool > hotkeys set a hotkey for Network Pane
- Paste the following code in the script tabe:
import hou

desktop = hou.ui.curDesktop()
pane = desktop.paneUnderCursor()
network_editor = pane.currentTab()
network_editor_type = network_editor.pwd().childTypeCategory()

# network context mapping to desktops
network_types: dict = {'Object' : 'Build', 
                       'Sop'    : 'Modeling', 
                       'Vop'    : 'Labs', 
                       'Dop'    : 'Technical', 
                       'CopNet' : 'Image'}
                     
if (network_editor != None):
    for network_type, desktop_name in network_types.items():
        if network_editor_type.name() == network_type:
            desktops_dict = dict((d.name(), d) for d in hou.ui.desktops())
            desktops_dict[desktop_name].setAsCurrent()
            break

With the network_type dictionary you can map network context to a desktop.
Use hotkey while under a network editor to change the mapped desktop.
Not sure if it is possible without pressing a key - there are some event handlers, but I didnt look closely.

Resources:
Is there a way to query the current context in Python? [forums.odforce.net]
hou.Desktop.setAsCurrent() [www.sidefx.com]
Edited by vikus - Aug. 6, 2024 18:15:47
User Avatar
Member
654 posts
Joined: Aug. 2014
Offline
That's brilliant, Viklc! I think it will be my most used script from now on. Many thanks for posting it.

If we could now use it as a callback function of desktop switching routines, or inject it somehow into them, the problem would be completely solved. I assume this would require HDK?
User Avatar
Member
247 posts
Joined: May 2017
Offline
I like the idea changing the desktop to match the network. In the last two days I jump from sops to lops all the time and don’t like to change the proper desktop manually as well. I use quickmarks and jump back and forth with it a lot - so for me it would already work to map the above function to the 1-5 keys.

ajz3d
If we could now use it as a callback function of desktop switching routines
There is for example the addEventLoopCallback [www.sidefx.com] which runs permanent once registered. But I dont think it is a good idea to compare always whether the current desktop matches the network context - but that should work. The best way would be to trigger a callback when you press something on the network, but the problem with that would be the query itself. Since if you trigger the function with a click, the network is probably still the same at that point, so you would need a post event or a delayed call.

I'll take a closer look at it over the next few days and let you know if it works.
User Avatar
Member
654 posts
Joined: Aug. 2014
Offline
viklc
There is for example the addEventLoopCallback which runs permanent once registered.
That's a very good find!

viklc
The best way would be to trigger a callback when you press something on the network
Note that there are multiple ways of changing paths: mouse clicks over path bars, "U", "I" and "Enter" keys, Quickmarks, the Dashbox, from Python Shell and scripts, etc. So the implementation might become complicated very fast (if possible at all with the current function set). Maybe addEventLoopCallback()is a good starting point after all? That is until we can figure out how to do it in a more optimal way, or after we place an RFE for required functions and our request is realized? I don't know.

addEventLoopCallback()is called every ~50 ms. I'm not sure if it would bog down the UI, but I think it can be delayed with waitUntil(). One second seems reasonable to me.
User Avatar
Member
247 posts
Joined: May 2017
Offline
ajz3d
addEventLoopCallback()is called every ~50 ms. I'm not sure if it would bog down the UI, but I think it can be delayed with waitUntil(). One second seems reasonable to me.
The parmanent query will certainly not affect Houdini, but it could cause a possible conflict an overlap with another function running in the background or something similar. So what we can try is to use one of the ui event reasons to first query if the user has pressed a key or mouse button and then ask if the current desktop matches the network context. But I'm not sure if the hou.uiEventReason [www.sidefx.com] works with the ui loop, I only used them with viewer states - this is probably the next step to find out.
User Avatar
Member
247 posts
Joined: May 2017
Offline
So everything is needed is actually described here: Extending the network editor [www.sidefx.com].
The basic organization of the code is that all events are passed to the current context module (nodegraph.py by default)…
There is a function called handleEventCoroutine() that can be used to query whether the network editor has been changed or generally catch all network editor events.

Go to $HFS/houdini/pythonX.Ylibs/ and open nodegraph.py, search for handleEventCoroutine(), then look for the isinstance(uievent, ContextEvent) statement and paste the following code directly below it:
# network context mapping to desktops
editor_desktop_map: dict = {'Object' : 'Build', 
                            'Sop'    : 'Modeling', 
                            'Vop'    : 'Labs', 
                            'Dop'    : 'Technical', 
                            'CopNet' : 'Image'}

current_editor_type = editor.pwd().childTypeCategory().name()
desktop = hou.ui.curDesktop()
if current_editor_type in editor_desktop_map.keys() and desktop.name() != editor_desktop_map[current_editor_type]:
    for editor_type, desktop_name in editor_desktop_map.items():
        if current_editor_type == editor_type:
            desktops_dict = dict((d.name(), d) for d in hou.ui.desktops())
            desktops_dict[desktop_name].setAsCurrent()
            break
Like this:


Then save the file and restart houdini now it should work automatically.

Attachments:
nodegraph.py.jpg (64.2 KB)

User Avatar
Member
654 posts
Joined: Aug. 2014
Offline
Fabulous work! Well done, Viklc!

Here's a patchfile that can be easily applied on a copy of nodegraph.pyin order to avoid editing it manually. I modified the script slightly to put the dictionary into a separate module named deskassign.pyfor easier editing. It must be placed in the same path as patched nodegraph.py, which should be either:
  • $HOUDINI_USER_PREF_DIR/python3.11libs,
  • or $HOUDINI_PACKAGE_DIR/somepackage/python3.11libs, if one wants to use a package.

On GNU/Linux the patch can be applied with:
patch nodegraph.py < nodegraph.py.patch
No idea how to do it on Windows.

Viklc, can you put your script on a git server?
Edited by ajz3d - Aug. 9, 2024 09:25:45

Attachments:
nodegraph.py.patch (1.1 KB)
deskassign.py (186 bytes)

User Avatar
Member
247 posts
Joined: May 2017
Offline
Thanks, and thanks for providing useful ideas and pushing.

You can find it now on Github as a package without modifying the original file. You can also use the generator wrapper to catch other editor events. Network-Context-Desktop-Mapping [github.com]
User Avatar
Member
6 posts
Joined: Dec. 2021
Offline
Greetings!

I've stumbled on this post and discover the script and package made by viklc and ajz3d. It works really well!


But I have one specific occurence when it doesn't work perfectly. It's when I switch from any context to LOP context. The desktop switches properly but the network goes back to /obj context or to the parent SOP level in case I dive inside a LOP Network. So I have to dive inside my /stage or LOP Network again.

I believe it's since Houdini 20 or 20.5 when switching to LOP, the current Desktop adapts to display Solaris and USD infos. Do you think this official behaviour could creates this conflict?

Thanks in advance!
Edited by TristanG - Oct. 6, 2024 07:12:29
User Avatar
Member
654 posts
Joined: Aug. 2014
Offline
I think this behavior comes from the fact that desktops, apart from pane layout, also store pane paths (if applicable). So, whenever we load a desktop, we also load these paths and that's when Houdini may force us out from the context we are currently in, if it's unable to find those stored paths in the loaded scene.

Perhaps it can be fixed with some additional logic. For example, to first check what are the paths in currently opened panes, and reset them after desktop loads. But, it's somewhat problematic. For instance, if current desktop has two panes with two identical contexts (LOPs, for example), but different paths, and the loaded desktop has only one pane supporting paths, which path do we drop? Things like that. Also, we would still see a brief switch from one path to another. Each solution I can think of comes with its own share of drawbacks.
User Avatar
Member
247 posts
Joined: May 2017
Offline
Hi TristanG,
I am glad you interested and hope it took not to long for the response. I also want you to know that I am working on a solution but have not had as much time in the last few weeks as there are some issues that need to be fixed.

Here some notes what is fixed and what has to be done:

At the moment the request for the desktop match is always triggered when something is changed in a network, so even if you change the desktop using the desktop dropdown menu, it can happen that you will drop to another desktop, as the network change event is also raised at this point. This is prevented by an additional query only under the mouse cursor, meaning that changes are only made if the user is currently under a network editor. This also solves the issue of multiple network change events depending on how many networks are currently present.

The other major issue is what ajz3d mentioned. So when you change the network context, the change event is fired, which will attempt to match the associated desktop, leaving the previous network where the change is made with the selected network context (network path); if you return to the previous desktop, the network is not matched.

There are two solutions for this:
  • before changing the desktop, reset the network path where the event is triggered, but this also triggers the network change event once again, which will lock the state. To solve this, we need to temporarily disable the event once before the reset.
  • the other option is to keep track of the network desktop, which would make it possible to reset the network context afterwards, this would also avoid to trigger the event again as we are in the correct desktop. But keeping track of the networks is not so easy. Each pane has a unique session id, but under certain situations the id can be changed and the tracking gets lost. This sometimes happens when you manually load another desktop or add a new one. I can't say exactly when - so probaly I need to contact side fx.

I will implement some user options, such as only take effect when changing the root path, obj, img, mat, and so on. In addition also like dops which are subnets. Also interactive mapping and management direct in houdini.

I can't say how long it will take, some things have already been done, but the main issue still needs to be solved.
Edited by vikus - Oct. 19, 2024 13:50:54
User Avatar
Member
247 posts
Joined: May 2017
Offline
So finally got something usable. Tried many things, but nothing worked well. Ended upwith a retrictive approach that works stable and also takes care of paths. You can now switch from nodegraph path or subnets and the path will be taken over. It also works interactive you dont have to set anything in the external file by hand, simply using a hotkey under a nodegraph, which then maps its context to the current desktop - you can also delete the mapping directly, so everything works on the fly. Read the readme file on github.

nodegraphdesk [github.com]

And thanks again to you guys for pushing forward. Let me know any issues or improvements - enjoy.
Edited by vikus - Oct. 22, 2024 06:56:58
User Avatar
Member
6 posts
Joined: Dec. 2021
Offline
Hi viklc,

Just tested the tool and it works like a charm! The only thing that could be really cool is to add a display message when a desktop is attributed, for user experience. But otherwise, it's super nice.

Thank you very much for your dedicated time and effort! Very inspiring!
User Avatar
Member
247 posts
Joined: May 2017
Offline
TristanG
he only thing that could be really cool is to add a display message when a desktop is attributed, for user experience.
Added a flash message that appears in the top left corner of the network editor when the user re/assigns or removes mapping.
User Avatar
Member
654 posts
Joined: Aug. 2014
Offline
Great work, Viklc.

The script works like a charm, but unfortunately only for root contexts (/obj, /stage, /chop, etc.) For instance, it does not trigger if you dive into SOP context located in /obj/geo1or CHOPs nested in /obj/geo2/lopnet1/chopnet1. It treats them all as /obj.

Do you think the program can be modified in such way that it also recognizes the type of nested networks, regardless of their location, or would it be too complicated?
User Avatar
Member
247 posts
Joined: May 2017
Offline
Hi nested networks works as well. Accept chops they dont trigger the network change event, cant say why, probably need to contact support - maybe an intersection with the coroutine.

I also have to notice that the mapping only works for the root path (context), so if you are in a nested network and try to map the context, the root (context) will be mapped. I will change this in the next update, also mapping for dops and so on.
Edited by vikus - Oct. 22, 2024 13:10:19
User Avatar
Member
247 posts
Joined: May 2017
Offline
Hm just tested with chops works as well, this was not the case before. So when you map context make sure you are in the root path of the network. The subnets will adopt this automatically. You can change the mapping for the subnets in configs subnetwork_context_map dictionary.

Edit:
Also make sure you are using the latest version, I did an update 1 hour ago where I removed the additional 'isUnderCursor()' query. That will also be the reason why chops didn't work as they are listed at top in the path dropdown menu, it's not in the nodegraph area to trigger the change event.
Edited by vikus - Oct. 22, 2024 13:36:59
  • Quick Links