We've Moved


The blog has been retired - it's up for legacy reasons, but these days I'm blogging at blog.theodox.com. All of the content from this site has been replicated there, and that's where all of the new content will be posted. The new feed is here . I'm experimenting with crossposting from the live site, but if you want to keep up to date use blog.theodox.com or just theodox.com
Showing posts with label mGui. Show all posts
Showing posts with label mGui. Show all posts

Saturday, March 26, 2016

mGui updates in the offing...

mGui updates in the offing... Changes on the way for mGui, the maya Gui framework

For those of you who’ve been using mGui to speed up and simplify your Maya gui coding, there are some interesting changes on the horizon. Although I’m not entirely ready to release the changes I have in mind they are mostly sitting in their own branch in the Github repo.

The upcoming version introduces some new idioms - in particular, it gets rid of the need for explicitly setting keys on new controls to get access to nested properties. In the first version of mGui you’d write something like this:

    with gui.Window('window', title = 'fred') as example_window:
        with VerticalForm('main') as main:
            Text(None, label = "Items without vertex colors")
            lists.VerticalList('lister' ).Collection < bind() < bound  
            with HorizontalStretchForm('buttons'):
                Button('refresh', l='Refresh')
                Button('close', l='Close')

With the new refactor that looks like this:

    with gui.Window('window', title = 'fred') as example_window:
        with VerticalForm() as main:
            Text(label = "Items without vertex colors")
            lister = lists.VerticalList()
            lister.collection < bind() < bound  
            with HorizontalStretchForm() as button_row:
                refresh = Button( label='Refresh')
                close = Button(label='Close')

The big advantage here is that those local variables are not scoped exclusively to the layout context managers where they live, which makes it easy to control when and where you hook up your event handlers: In the above example you could defer all the bindings and event handlers to the end of the script like this:

    with gui.Window('window', title = 'fred') as example_window:
        with VerticalForm() as main:
            Text(label = "Items without vertex colors")
            lister = lists.VerticalList()
            with HorizontalStretchForm() as button_row:
                refresh = Button( label='Refresh')
                close = Button(label='Close')

    lister.collection < bind() < bound
    refresh.command += refresh_def
    close.command += close_def

So far I’m really liking the new idiom, particularly eliminating the extra quotes and redundant None keys. However this is a minorly breaking change: in some cases, old code which relied on the key value to name and also label a control at the same time will when the keys become redundant. Moreover I bit the bullet and started to refactor the entire mGui module to use correct pep-8 naming conventions – in particular, member variables are no longer capitalized. So if you have code outside of mGui this will introduce some issues. When I converted my own code, most of the changes could be done with a regular expression but there were a few danglers.

I think the changes are worth the effort, but I’d be really interested in hearing from users before trying to bring the new mGui branch back into the main line. It should actually be possible to write a script that fixes most existing code automatically, that’s something we could refine collaboratively.Please let me know in the comments or by opening an issue on the GitHub site if you have comments or plans. As always, bug fixes and pull requests always entertained!

Tuesday, June 24, 2014

mGui updates

For anybody whos been following the mGui Maya GUI construction kit posts, I've added a few fixes and tweaks to the GitHub project in the last couple of weeks:


mGui.progress

The progress module wraps Maya's progressBar command for mGui style coding of progress bars.

There are two classes in the module;  ProgressBar  is the generic version and MainProgressBar always points at Maya's main progress bar.  Both classes have start(), update() and end() methods instead of Maya's clunky cmds.progressBar(name, e=True, beginProgress=1)  and so on.  They also both have an iter method, which will loop over a generator expression and update the progress bar for each yield then pass along the value. This allows simple idioms like:


from mGui.progress import MainProgressBar
import os

def list_files(dir):
    # pretend this is as long, slow function...
    for item in os.listdir(dir):
        yield item

pb = MainProgressBar()
for each_file in pb.iter(list_files()):
    print each_file.upper()
    # here's where you do something with the results


So you can update the progress bar without unduly intertwining the GUI update and the program logic.

mGui.menu_loader

The menu_loader module will create menus from a YAML data file.  It does a little bit of introspection to figure out how to create the items and attach their handlers to functions. This makes it easy to set up a menu with several items from a single setup routine.

The menu data is a text-based YAML file that looks like this:


!MMenu
    key:   UndeadLabs
    label: Undead Labs
    items:
        - !MMenuItem
            key: About
            label: About Undead Labs...
            annotation: "About this UndeadLabs tool setup"
            command: tools.common.aboutDialog.open

        - !MMenuItem
            key: RemoteDebugger
            label:  Remote Debugger
            annotation: Start / Stop remote python debugger
            command: tools.common.remoteDebug.remote_debugger_dialog


And loading the menu is as simple as:


import mGui.menu_loader as loader
loader.load_menu('path/to/undeadlabs.YAML')


mGui.scriptJobs

The scriptJobs module adapts the event model for use with scriptJobs. A ScriptJobEvent is a derivative of Event which allows you to hook multiple handlers to a single scriptjob (in the same way that the other Event classes allow for multicast delegates):

from mGui.scriptJobs import *

def print_selected (*args, **kwargs):
    print cmds.ls(sl=True) or []

sj = ScriptJobEvent("e", "SelectionChanged")
sj += print_selected

As with all the mGui Event classes, you can add multiple handlers to  single event:

sj += some_other_function()

The module also includes named subclasses to simplify setup. That way you can do things like:
closing_sj = RecentCommandChanged()
closing_sj += close_handler

which is a bit nicer and less typo prone if you use an autocompleting IDE.



Tuesday, April 29, 2014

The Main Event - event oriented programming in Maya

The Maya Callbacks Cheat Sheet post started out as an effort to explain the design the event system in mGui - but it quickly turned into it's own thing as I realized that the vanilla Maya system remains confusing to lots of people.  With that background out of the way, I want to return to events proper, both to explain why they work the way the do in mGui and also how they can be useful for other projects as well (I use them all over the place in non-GUI contexts).

...and, because it's got the word 'event' in it, I'm going to throw in a lot of irrelevant references as I can manage to The Crushah!





Wednesday, April 23, 2014

Maya callbacks cheat sheet

Update 5/7/14: Added a note on closures and lambdas

In All Your Base Classes,  I suggested that we can do better than the standard callback mechanism for doing Maya event handling.  The limitations of the default method are something I've complained about before, and if you follow these things on TAO or CGTalk or StackOverflow it seems pretty clear that a lot of other people have problems with the standard Maya code flow too.

I was planning on devoting the next big post to the event mechanism in mGui . However as I did the spadework for this post I decided it was better to split it up into two parts, since a lot of folks seem to be confused about the right way to manage basic Maya callbacks. Before moving fancy stuff, it's a good idea to make sure the basics are clear. Most vets will already know most of what I'm going over here, but I found the  time spent laying it out for myself a useful exercise  so I figured it would be worth sharing even if it's not revolutionary.