theodox / mGui

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

Possible method of making Compound Controls #84

Closed bob-white closed 6 years ago

bob-white commented 7 years ago

Initial example is an IntSpinner. Based on the conversation over at TAO

Basically just expands the IntField with a new step value, and links the two buttons to increment and decrement the value.

from mGui import gui, forms, core
from mGui.core.compound import IntSpinner

with gui.Window() as win:
    with forms.VerticalForm() as main:
        spinner = IntSpinner(width=256, height=24)
        gui.Separator()
        spinner2 = IntSpinner(width=256, height=24, step=5)

win.show()

If we want to further expose the button commands, we'd need some kind of descriptor to route the Events from the sub commands, but that should be fairly simple.

theodox commented 7 years ago

In other words:: I'd like to write a class without too much custom code where my compound thing has a tree of widgets:

  Root
      - label
      - field
      -form 
          -up-button
          -down-button

and have a nice, clean and clear way of setting properties on root.form.down-button wiithout needing to know that internal strucuture -- something like compound.decrement.backgroundColor = xxx from the user side even though its root.form.down-button.backgroundcolor = xxx under the hood

The tricky bit is how to make inot too painful to set up, ideally with a nice metaclass to make it really uncluttered

bob-white commented 7 years ago

So something along these lines

class CompoundControlMeta(type):
    # Some magic will happen here
    pass

class CompoundControl:
    __metaclass__ = CompoundControlMeta

class IntSpinner(CompoundControl):

    _CONTROLS = {
        'root': HorizontalStretchForm,
        'field': IntField,
        'label': Text,
        'decrement': Button,
        'increment': Button,
        'form': VerticalStretchForm,
    }
    _HIERARCHY = {
        'root': (
            'label',
            'field', {
                'form': (
                    'increment',
                    'decrement'
                )
            }
        )
    }

CompoundControlMeta would need to walk _CONTROLS to generate the widget properties for routing those properly. It would also need to be able to walk _HIERARCHY to generate the actual internal layout.

Other issues:

bob-white commented 7 years ago

Also something like this might benefit from #65. Or maybe something closer to the kv DSL from kivy.

theodox commented 7 years ago

I think I'm OK with the compound widget assembly process being code rather than data -- the list classes, which are effectively examples of compound widgets, needed some finagling to work the way I liked. At this early stage of the idea it feels like the main issue is a painless way for the owning compound object to expose properties correctly -- some of them will be unique to the compoiund and need custom code but some will basically be pass-throughs of properites on lower level stuff.

I've been assuming that the widget of the compound is going to be the root of the underlying pieces, so you can set things like position, size and so on easily

bob-white commented 7 years ago

Updated the PR with just another thought. Instead of subclassing any mGui object, this acts more as a facade. It uses __getattr__ and __setattr__ to route attribute lookup to the root object, if a field happens to exist there, otherwise it defaults to normal behavior. Also, given the way __getattr__ works, anything that already exists on the facade gets precedence.

Each of the controls is exposed as a public field, so no need to generate properties to route information to them.

Still have to manually generate any IntSpinner specific code though, which seems like a place where we can probably get a metaclass involved to simplify it.