theodox / mGui

Python module for cleaner maya GUI layout syntax
MIT License
123 stars 23 forks source link

Qt compat #68

Closed bob-white closed 7 years ago

bob-white commented 7 years ago

Initial pass at #63. This provides a compatibility module that helps to smooth over all the potential Qt-bindings. Updated the various Qt enhanced classes to use this new module. Added a QtSignalProperty that acts similar to the CallbackProperty, except it works on top of QtSignals.

theodox commented 7 years ago

So Bob, which versions of Maya / QT have we tried so far?

bob-white commented 7 years ago

So I did some basic testing in both 2016 and 2017. And I tested against both pyside and pyqt for each version. I probably tested the pysides a bit more heavily, but I ensured that the as_qt_object, and the main_window functions worked with all 4 binding options.

Currently it the qt._compat module prefers PySide, and doesn't really have a mechanism to override this if someone really, really wants to use PyQt instead. Not sure if this is worth worrying about, given that its really for internal mGui use only. Mostly the PyQt stuff is there just in case someone has removed any reference to PySide from their install.

It also tries to present a more Qt5-esque layout, currently this is dirt simple and just aliases QtGui to QtWidgets.

theodox commented 7 years ago

one more thing - does this provide a platform agnostic way to read designer files?

bob-white commented 7 years ago

It does not. I've not used those very often, so kind of forgot they were a thing. I'll look into that though.

bob-white commented 7 years ago

Added a load_ui function. This works similar to the as_qt_object function by hiding the different binding's ui loading options behind a single interface.

Tested with PySide/PyQt4 in Maya2016, and PySide2/PyQt5 in Maya2017.

bob-white commented 7 years ago

Potential solution to #66

from mGui import gui, forms
from mGui.qt.QDialog import ModalDialogWindow

with ModalDialogWindow() as win:
    with forms.FooterForm() as base:
        with forms.FillForm() as main:
            text = gui.TextField()

        with forms.HorizontalStretchForm() as footer:
            okay = gui.Button(label='Okay')
            cancel = gui.Button(label='Cancel')

            okay.command += win.accept
            cancel.command += win.reject

def _accepted(*args, **kwargs):
    sender = kwargs['sender']
    print(sender.base.main.text.text)

def _rejected(*args, **kwargs):
    print('Rejected!')

win.accepted += _accepted
win.rejected += _rejected

win.show()

This creates a blocking modal dialog similar to what we'd get with cmds.layoutDialog but without having to jump through the weird function based API baggage that it drags into the equation.

Also, unlike cmds.layoutDialog these dialogs can open other ModalDialogWindows, and control is passed to the most recent, which then unwinds as you work through them.

theodox commented 7 years ago

Can we come up with a way to make sure that there's no way to accidentally create a ModalDialogWindow() with no way to dismiss?

bob-white commented 7 years ago

Both DialogWindow and ModalDialogWindow can be dismissed by just closing the window, which will then trigger the rejected event.

So an explicit button or some other control isn't necessary to actually close the dialog.

I also added support for the retain flag so that by default closing the window deletes the underlying widget.

theodox commented 7 years ago

I wish I felt confident enough in my QT-foo to pass judgement on this. It's "safe" to merge insofar as -- from a selfish perspective -- I know it won't hit anything I'm using at work. How do you feel about the functionality? Are you using it extensively at work ? Do you know any mGui / QT folks we can guinea pig with?

bob-white commented 7 years ago

Been using the ModalDialogWindow stuff at work pretty heavily recently, updated our perforce related dialog windows over to them. So much nicer to work with vs cmds.layoutDialog.

So all the underpinnings are definitely functioning.