Git Product home page Git Product logo

mgui's People

Contributors

bob-white avatar jasonminters avatar kartikg3 avatar mambo4 avatar theodox avatar undeadbryce avatar zackaroni avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mgui's Issues

tabLayout management sucks

Maya's default tabLayout management is pretty nasty: like formLayout it involves a lot of retrospective editing

What's the right way to clean it up?

right now you could do
with TabLayout("fred") as tabs:
with FormLayout("xxx") as tab1:
Button("example")
with FormLayout("yyy") as tab2:
Button("example")
tabs.tabLabels = ((tab1, "XXX"), (tab2, "YYY"))

but it would be nice if you did not have to. Could we:

  • auto-generate tab names from the child names?
  • add an optional tabName property to all controls that they use if when inside tabs?
    with TabLayout("fred") as tabs:
    with FormLayout("xxx", tabname = "XXX") as tab1:
    Button("example")
  • add a setname function:

with TabLayout("fred") as tabs:
with FormLayout("xxx") as tab1:
Button("example")
tabs.setname(tab1, "xxx")

other ideass?

YAML - like layout language?

What do people think about a Yaml-like declarative layout format for saving GUI as data? Is that a step forward or back? mGui.MenuLoader is great for menus, since there's a lot of boilerplate in making menus. Is it worth extending as whole layouts?

Single instance Windows

HI!:

It looks like the main window is auto-named (window8, window9, etc.) when instantiated . How can I implement a single instance window? The usual way is to use window name together with deleteUI command to ensure that there is only a single instance window.

There are couple idea I am thinking about:

  1. use Maya's global variable as registry for window's name
  2. use Python module level variable to register window'name

Maybe I miss something here, can you guys help out?

Thanks.

Add QTPy support

If we're going to keep things like the mGui.qt going forward we'll need to transparently support post Maya 2017. I think QTpy is the likeliest way forward. Thoughts?

wanted: bindable TextScrollList

The default TextScrollList is just the maya one, which does not allow bulk set of items. Need to come up with a property wrapper that allows binding to a collection and under the hood deletes and rebuilds the collection without making user do that every time.

2016 breaks LayoutDialogForm

It looks like everything happening in a LayoutDialogForm is deferred, so the UI is gone before any handlers are invoked. This is true even if you explicitly replace the MayaEvents with Events, which makes no sense to me. Need to investigate further

mGui/mGui/examples/filtered_collection.py ImportError

mGui/mGui/examples/filtered_collection.py
cmds.scriptJob(lj=True)
# Error: ImportError: file <maya console> line 9: No module named ul_profile # 

mGui/mGui/examples/filtered_collection.py ImportError

seems fixed by removing line 9
from ul_profile import do_cprofile

CSS targeting via key does not work in context manager

I just noticed that the CSS feature targeting keys is not working in 2.2. I think this probably broke with 2.0, since the problem is that CSS.applies is looking for keys -- but since 2.0 the keys on an mGui control are set retroactively, not during the __init__ of any particular widget.

So this does not work:

 example = CSS ('named_item', backgroundColor=(1,0,0)

with example: 
       with FillForm():
               named_item = Button('should be red')

but this still does

     example = CSS ('named_item', backgroundColor=(1,0,0)
     with FillForm() as outer:
          named_item = Button('should be red')

     example.apply_recursive(outer)

and so does this:

 example = CSS ('named_item', backgroundColor=(1,0,0)
 with FillForm():
        named_item = Button('should be red', css = example)

I'm not sure if its worth resurrecting this feature. It's supposed to be an analogy to the "id" selector in regular CSS. However since a CSS object can be passed directly to a constructor, user can work around it like that. alternatively we could add an explict 'selector' kwarg, but that seems like overkill. I don't make much use of the string id target feature, so I won't mind if we just remove the documentation that talks about it .

What do other people think?

Data driven shelves

It would be nice to have something akin to mGui.menuloader for shelves, allowing good support for data-driven shelves

A better alternative to keys

I really like the access to children: man.root.header.button1 is a nice, natural idiom. But I hate all the quotes involved in typing

  Button("my key")

So I'm thinking about using the context manager hack in plugger to make variable style assignments instead

with FormLayout() as root:
    button = Button(label = 'xx')
    field = TextField()

were the context manager close-over does what is currently done by the keys

Layout.clear doesn't remove all child controls in Maya 2018

I'm dynamically generating controls under a VerticalForm. I've been trying to use the form's clear() method when I need to refresh the UI, but some of the controls aren't removed. I tried poking around in the code, and it looks to me like the culprit is the generator expression in mgui/core/init.py line 350. It looks like it's removing controls from the list as it's reading from the list, and some controls get skipped as a result.
Replacing the generator expression with a list seems to work. I'll create a pull request with that change.

MayaEvent() handlers don't work properly in LayoutDialogs

By default mGui widgets are created with MayaEvent() objects as their event delegates. Ordinarily that's nice because it minimizes damage from UI reacting across threads...

but it also means that the events for a widget created using cmds.layoutDialog don't fire until after the dialog closes, since we never hit the idle state while the dialog is open.

The workaround it to replace the MayaEvent() with an Event() -- that's synchronous so it doesn't get hung up. Here's an example:

    def _layout(self):
        with forms.LayoutDialogForm('root') as self.root:
            with forms.VerticalThreePane(None):
                gui.Text( label='Please log into Perforce. This is only required once per project.')
                with forms.VerticalExpandForm(None):
                    gui.Text( label='Enter your p4 client workspace. E.G. "bryce-class4"')
                    self.p4Client = gui.TextField('P4ClientWorkspace')
                    gui.Text( label='Enter p4 user name. E.G. "Bryce"')
                    self.p4User = gui.TextField('P4UserName')
                    gui.Text( label='Enter p4 password.')
                    self.p4Password = gui.TextField('P4Password')
                    gui.Text( label='Enter p4 port.')
                    self.p4Port = gui.TextField('p4port', text='p4proxy.undeadlabs.net:1667')
                login_button = gui.Button('login', label='Login')
                login_button.command = Event()
                login_button.command += self.attempt_p4_login

where the login_button is post-edited to switch types. That's an annoying piece of trivia for users to remembr

$tmp MEL variable clash

This is probably an edge case, and may not affect everyone, but it is worth fixing in my opinion.

The mel variable $tmp is being used to get $gMainProgressBar. Since $tmp is a common variable for getting global variables from MEL to Python, this could cause variable type clashes, causing the Main Progress Bar code to fail if that variable was already declared in some other tool/code.

A new trick to avoid dead reference errors

I've been toying with an idea for getting rid of dead ref errors without needing users to make classes.

Basically it looks like this:

    with BindingWindow(title = 'example window') as test_window:
        bound = ObservableCollection("A", "B")

        with VerticalForm() as main:
            Text(label = "The following items don't have vertex colors")
            list_view = VerticalList()
            list_view.bind.collection < bind() < bound
            with HorizontalStretchForm('buttons'):
                refresh = Button('refresh', l='Refresh')
                close = Button('close', l='Close')

    def close_window(*_, **__):
        cmds.deleteUI(test_window)

    def refresh_window(*_, **__):
        list_view.redraw()

    test_window.refresh = refresh_window
    test_window.close = close_window

    refresh.command += test_window.refresh
    close.command +=  test_window.close

by making test_window.refresh and test_window.close members of the object test_window, they don't fall out of scope but they don't need to be regular instance methods with self. I was thinking we could extend the handler syntax so it automatically did this for the user, so maybe:

 refresh.command *= refresh_window  

would add the static function refresh_window as a member variable (on refresh maybe instead of on the window), keeping it alive as long as the widget lived.

Thoughts?

Figure out some way to get _real_ text changed events from textFields

Maya's text field does not send a notification on content changes - only for enter/return key or when the user changes focus. This means that callbacks on changes to text content don't get fired if the user does not tab/return out of the field. So, if you have a button that closes your window, and are relying on bindings to get your text fields, you will never be notified that the text in a text field has changed if you ciick the window close button or another piece of UI that tries to close the window.

AFAIK the only way around this would be to use PySide to grab the underlying QT widget and manually hook the appropriate event (the QT widget should have more events than the Maya wrapper around it does).

Thoughts? Suggestions?

best idiom for dealing with existing controls

in a couple of places the current code uses this idiom to work with existing controls:

 @classmethod
 def from_existing(cls, widget):
      try:
      _cache = cls.CMD
      def fake_CMD(*args, **kwargs):
            return widget
      cls.CMD = fake_CMD
      return cls(widget, widget)
      finally:
           cls.CMD = _cache

This seems to work, but I'm nervous about it. It won't be thread safe (not a major concern - the gui stuff is thread hell no matter what) and it will need extra work for things like parsing existing menus with submenus....

to pep-8 or not to pep-8?

The current style is pep 8 with the exception of field names, which are captialised. Nowadays this bugs me. Fixing is a pretty major refactor, however, since it touches pretty much all existing code.

Who cares? Sound off!

Feature Idea: Outside drag and drop

We currently support Maya's limited internal drag-and-drop callbacks. however these don't work for drags from outside of Maya -- you can't for example drop a folder from Explorer onto a button and get a callback to fire.

I'm ambivalent about supporting this, because it's another QT-only feature. how complicated would it be to implement, assuming we decided to do it?

Wrapping optionMenuGrp

Noticed we haven't yet wrapped cmds.optionMenuGrp, I was going to do an initial pass on it, but noticed that all of our MenuGrp related classes inherit from Labeled, which is over in controls.

Would it make sense to move Labeled over to core? Or should I just import it from controls?

MenuItemProxy fails during instantiate()

I'm getting this error when trying to load a shelf:
# AttributeError: 'MenuItem' object has no attribute 'itemArray' //

It looks like the problem might be with the change to a self.proxy.wrap call in the previous line. Reverting that to gui.PopupMenu.wrap seems to fix it.

dead references to tools in scripts

because the event handlers need a live reference to something they will die if you create a window in a script and it falls out of scope:

class XXX(Window):
       def__init__(key, *args, **kwargs):
              # etc

      def show(self):
           self.Window.show()

def test():
     XXX().show():   # window appears but handlers fail, since the XXX we  make
                             # here falls out of scope immediately

You can work around this easily:

class XXX(Window):
ALIVE = []
def__init__(key, _args, *_kwargs):
# etc

      def show(self):
           self.Window.show()
           self.ALIVE.append(self)  # new instances stay in scope forever

but this keeps all instance around forever, which is equally annoying.

What to do?

_set_stylesheet fails if passed a dictionary

    def _set_stylesheet(self, css):
        if not isinstance(css, CSS):
            css = CSS(**css) # <<-- Lacks a target argument
        self._style = css
        css.apply_recursive(self)

Not sure what an appropriate substitute key would be here, though maybe self.key is workable?
Or we could raise TypeError if not passed a CSS instance.

Overriding Nested.__exit__ breaks the key-less idiom

This currently breaks BindingWindow when operating with the key-less idiom, but would apply to anything else that might override Nested.__exit__.

import mGui.gui as mg
import mGui.forms as mf

with mg.BindingWindow() as win:
    with mf.VerticalExpandForm() as main:
        btn = mg.Button()
win.show()
win.main.btn.label = 'I fail here'
# AttributeError: 'BindingWindow'' has no attribute 'main' # 

So in the above example when win's BindingWindow.__exit__ method is called, it then calls into Nested.__exit__, from there we grab the parent frame, which turns out to be BindingWindow.__exit__, and not the actual context scope we were hoping for.

Problem instantiating menus with menu_loader.py

Original report here:

am trying to run mGui.menu_loader with a yaml file, copying the example you show in your post,
and yet I can't.
I have the error
Error: AttributeError: file D:\packages\mayaBase\mGui\menu_loader.py line 173: 'str' object has no attribute 'instantiate'
Maybe I forgot something ...
I have the latest Pyyaml version installed (3.12)

The disqus link for the blog post this was attached to is busted, so creating this for tracking.

'VerticalListForm' is not defined

There seems to be no VerticalListForm as per your code in the readme.

import mGui.gui
import mGui.observable as obs
from mGui.bindings import bind, BindingContext

bound = obs.ViewCollection(pm.PyNode("pCube1"), pm.PyNode("pPlane2"))   

with gui.Window('window', title = 'fred') as example_window:
    with BindingContext() as bind_ctx:
        with gui.VerticalForm('main') as main:
            Text(None, label = "The following items don't have vertex colors")
            VerticalListForm('lister' ).Collection < bind() < bound  
            with HorizontalStretchForm('buttons'):
                Button('refresh', l='Refresh')
                Button('close', l='Close')
example_window.show()

Threaded property access

In the threaded branch, it appears safe to, say, asynchronously update an observableCollection and have it update the UI - however making all the property accessors use EvalDeferredInMainThreadWithResult means that you get long hangs and some dependent layout items don't work properly because, I suspect, the layout items don't have sizes yet.

It would be really nice not to have to think about this at the user level at all. How to get there?

Heads up on popupmenus

I noticed and fixed an issue with mGui 2.2 and popup menus . The new and improved menu syntax had the side effect of making popups not get added to their owning widgets -- which made them get garbage collected, so any references to themselves (like kwargs['sender']) would result in dead reference errors.

I've fixed it already in e8378c0 but if you run into that you may need to catch up on that commit

recursive application of `wrap()`?

Relating to the earlier discussion #77 -- should we extend the strategy in #79 for getting wrapped editors from wrapped panels so that all wrapped mGui controls recursively generate wrapped children? What pros and cons there?

Reference leak in windows (maybe others)

it seems impossible to trigger a del on a class derived from Window, at least if there are events attached to it. Somebody other than event handler is maintaining a link to the class and thus even del(self) does not remove it from memory. This should be cleaned up ASAP

mGui\examples\simple.py Error

testing example files:
executing
\mGui\examples\simple.py
produces
# Error: AttributeError: file line 46: 'module' object has no attribute 'HorizontalStretchForm' #

It seems mGui.Forms is not being imported. There are a few other forms objects referenced in the code.

Add absolute references to names

We track names for path access. We should also track allow some method to generate variables on the top level control of a group that tells parent controls to collect it. Here's the idiom i have in mind:

with Window('root') as w:
    with FillForm('ignoreme'):
          with HeaderForm("ignoremetoo")
                Button ("@important")

 w.important.command += do_something

but we'd keep existing behavior so w.important would be the same as

w.ignoreme.ignoremetoo.important 

Need a way to bind styles

It would be good to have a simple, generic method to bind a CSS style to a value so that the value could be updated using bindings without extra imperative code.

Maybe make the a style_binding property that applied an incoming value?

Need a nice way of parameterizing events

Right now Events are created on controls when they are first attached. If you want to parameterize them you need to get them from the Callbacks dictionary:

with gui.Window('main') as example:
    with gui.VerticalForm('form'):
        for item in cmds.ls(type='transform'):
            b = gui.Button('b_' + item, label = item)
            b.command += move_down
            b.Callbacks['command'].Data['target'] = item

It would be great to be able to explicitly create a paramterized event:

with gui.Window('main') as example:
    with gui.VerticalForm('form'):
        for item in cmds.ls(type='transform'):
            b = gui.Button('b_' + item, label = item)
            b.command = MayaEvent(target = item)

but this won't work with the current setup. How to fix...?

Version specific controls?

How do we want to handle version specific codes?

I was looking at adding a wrapper from cmds.workspaceControl and it's related friends, but they only exist in 2017+ so we'd need some way to signify that constraint.

Easiest option would be inside an if MAYA_VERSION >= 2017 style block.
Though a separate module could also work.

Layout dialog enhancement

would be nice to have LayoutDialog class to go with LayoutDialogForm and make modal dialogs a bit less wonky

need better documentation for list event forwarding

TODO: have to write better examples of how lists.Templated and onWidgetCreated handle event forwarding from lists. The documentation there is correct as far as it goes -- but far from detailed enough for a N00b

Build logging support

Do you think we should replace all print statements of tracebacks and user feedback to use Python's logging API?

Help about TreeView

Hi, I have a problem with TreeView control.
I want to connect a function to the TreeView buttons like you do with the normal Button.

My sample code:

This inside the main init function

treeViewTest = gui.TreeView('Viewer', numberOfButtons=2)
treeViewTest .addItem = ('Work1', '')
treeViewTest .pressCommand += self.buttonAction

This what button should call function

def buttonAction(self, _args, *_kwargs):
template = kwargs['sender']
print template

ERROR MESSAGE:
TypeError: Invalid arguments for flag 'pressCommand'. Expected ( int, string or function ), got MayaEvent

But if I do like this:
treeViewTest .pressCommand =[(1,self.buttonAction),(2,self.buttonAction),(3,self.buttonAction)]
It does work but I cant get the sender. Which button I clicked on etc...
Only the arguments the controller sends.

This is the example when you connect with button controller and that works:
buttonTest = gui.Button('Reset to Default')
buttonTest .command += self.buttonAction

Probably I write something totally stupid wrong, so please teach me why this do not work.
And how you would solve this situation.

Best regards, Mattias Eriksson.

MenuItemProxy items fail to register internal callables

CallbackProxy instances created via the get_weak_reference factory method don't have the correct name attribute of their internal function object.

Traceback (most recent call last):
  File "C:\ULDev\source\ulMaya\external\mGui\mGui\menu_loader.py", line 165, in instantiate
    new_item.command += cp
  File "C:\ULDev\source\ulMaya\external\mGui\mGui\events.py", line 87, in _add_handler
    self._Handlers.add(get_weak_reference(handler))
  File "C:\ULDev\source\ulMaya\external\mGui\mGui\events.py", line 237, in get_weak_reference
    return WeakMethodFree(f)
  File "C:\ULDev\source\ulMaya\external\mGui\mGui\events.py", line 213, in __init__
    self._ref_name = f.__name__
AttributeError: 'CallbackProxy' object has no attribute '__name__'

Duplicate functions?

so,,, which of these is the right one? Looks like a merge issue creating two versions of the same idea

    @classmethod
    def wrap(cls, control_name, key=None):

        def _spoof_create(*_, **__):
            return control_name

        try:
            cache_CMD = cls.CMD
            cls.CMD = _spoof_create
            return cls(key=control_name)

        finally:
            cls.CMD = cache_CMD

    @classmethod
    def from_existing(cls, key, widget):
        """
        Create an instance of <cls> from an existing widgets
        """

        def fake_init(self, *_, **__):
            return widget

        _cmd = cls.CMD

        try:
            cls.CMD = fake_init
            return cls(key)

        finally:
            cls.CMD = _cmd
```

List speedup

This is just a notification: I reworked the way lists work, and they appear to be way, way faster. It turned out that QT really did not like lots of edits on child controls: just deleting containers and rebuilding them was far easier.

Wanted: GUI test harness

It would be great to have a way of verifying between builds that mGui is visually consistent. Perhaps doing a pixel diff on screenshot dumps or something like that? Howe would this work?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.