Dynamic ui loading

hey guys,

im starting on a general UI at work to avoid the increasing number of various UI’s for different tools, and was wondering if i could grab advice (maya,python)?

Were thinking of a single main UI that’ll dynamically load the necessary tools + rights based on the user and their needs, hoping it might be the better solution to just append to the existing UI than re-create UI’s all over the place, taking up more estate, and hopefully keeping things organised and easier to update.

current working process seems to be - searching for available modules/tools, filter their tags against the user and needs, load the module with import and draw the module’s UI parented to the main GUI’s tabLayout.

Im wondering if im on the right track with this? - all is working so far so good, im just curious as to whether anyone might have some tips?
(btw im not thinking that EVERY tool should be under this main UI, considering the sheer variation and limitation we would encounter, im thinking generic toolsets for Modelling, Texturing, Rigging, Animation etc)

Thanks guys

I created something similar in our world editor’s main properties pane, which shows different sets of controls based on what object(s) are selected. I used Python, which is embedded in our application.

First, at application startup it imports all modules sound in certain directories. Each one contains one/more groups of controls, which are written as subclasses of a common base class (call it Foo_Base). When the modules are all loaded it calls “Foo_Base.subclasses( )”, which returns a list of all known UI subclasses of that base that were “registered”. This is basically a dead-simple plugin system, and allows different teams to easily add more UI groups without altering the core code.

On each of those subclasses is a static method called “is_valid( obj )”. This accepts a world editor object as its only argument and returns a boolean (or other value that evals as one) determining if that set of UI controls is valid for the object. Every time the user’s selection changes in the world editor, the main properties pane code calls these and builds a list of valid UI groups for the selected objects. So a spline object returns True from “is_valid” on the UI groups related to spline editing, but False from the groups of mesh controls, etc. Since that is_valid is called on the subclasses objects returned above (not on instances of those classes) it’s marked with the @staticmethod decorator, and does not have “self” as first argument.

The properties pane code now has a list of all UI groups that are applicable to the objects in the user’s selected objects. To keep the UI code complexity down, and simplify things for the user, it omits any that are not valid on all selected objects. So if you have 9 splines selected and 1 mesh selected, it will not show the spline controls UI group.

The pane code then creates wx.FoldPanelBar objects (wxPython class similar to collapsible rollouts in 3ds Max) for each valid UI group, ordering them vertically by a “weight” value assigned to each, and renders them all in a vertical scroll panel.

The end result is a context-based collection of UI control groups relevant to the things you’re working on. I’ve been happy with this approach, and have used something similar in other context-sensitive interfaces.

[QUOTE=Adam Pletcher;16638]I created something similar in our world editor’s main properties pane, which shows different sets of controls based on what object(s) are selected. I used Python, which is embedded in our application.

First, at application startup it imports all modules sound in certain directories. Each one contains one/more groups of controls, which are written as subclasses of a common base class (call it Foo_Base). When the modules are all loaded it calls “Foo_Base.subclasses( )”, which returns a list of all known UI subclasses of that base that were “registered”. This is basically a dead-simple plugin system, and allows different teams to easily add more UI groups without altering the core code.
[/QUOTE]

We have a system almost word for word of what you wrote.

One difference I see with ours is we used a node plugged into an asset root (like what Bungie was/is using for modular rigging entry).

The node(s) also carry an ID to link up external data for all manner of light presets, posing, etc…

It is extremely easy to add new “editors” to this system and completely cleans up the interface.

Highly recommend using an approach like this.

we got something similar here as well, plugin based - we got a folder with an init.py, inside we have more folders. Each of those makes up a “plugin”. Each of those has a data handling module, a ui module and some custom module. We then dynamically import those modules with import and add them to an array.

So yes, this seems to be the way to go :slight_smile:

@Adam Pletcher

When the modules are all loaded it calls “Foo_Base.subclasses( )”, which returns a list of all known UI subclasses of that base that were “registered”.

That sounds pretty useful, im assuming the same method may work for packages?

@Amorano

The node(s) also carry an ID to link up external data for all manner of light presets, posing, etc…

Yeah i’ll be using metadata nodes into certain UI elements in an attempt to keep things smart, especially rig side :slight_smile:

@RobertKist

we got something similar here as well, plugin based - we got a folder with an init.py, inside we have more folders

Yeah packages are what I’d like to go with for maintaining organisation and keeping things flexible, I’m aware my knowledgebase is still off from what I’d need to complete a task like this, but simplicity, organisation, flexibility and documentation (not necessarily in that order) are the main things im trying to achieve to make it easier on myself and co-workers down the line.

Cheers guys, really appreciate your advice.

[QUOTE=ldunham1;16650]@Adam Pletcher
That sounds pretty useful, im assuming the same method may work for packages?[/QUOTE]

Yes, assuming you have code somewhere to auto-import all modules in those packages prior to doing the Base.subclasses() call. That method doesn’t care where/when the subclasses came from as long as they’re defined/known.