Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contract #2

Open
mottosso opened this issue Oct 6, 2016 · 9 comments
Open

Contract #2

mottosso opened this issue Oct 6, 2016 · 9 comments
Labels

Comments

@mottosso
Copy link
Member

mottosso commented Oct 6, 2016

Hi @BigRoy and @morganloomis!

Let's have a conversation about the requirements of our tools and what a platform such as Maya Control would need to facilitate for our tools to flourish.

If you could take a moment to look at the tools you've built already, and think about what they need.

For example, I know my tools will require at least:

  1. A Python module to be accessible on sys.path
  2. An (optional) hotkey to be associated with the module/part of the module
  3. An (optional) menu item, either an independent menu, and an item within an existing menu, such as "Deformers".

In Sublime, their superclass also supports getting notified of events, such as when a new document is opened, when the user is scrolling, or when the window is resized.

class MyPlugin(sublime_plugin.EventPlugin):
  def onWindowResized(self):
    print("Window resizing..")

Could this be interesting to us as well? Perhaps provide an interface to the callbacks provided by the Maya API and scriptJob's?

Perhaps equally important, what shouldn't a plug-in do?

I know for one thing that every plug-in must be self-contained; no dependencies. A plug-in should not block or cause a deadlock and not contain any absolute paths. We could automatically test for some of these upon accepting a new project into the channel.

What do your tools need?


Summary

Here I'll be updating with what we've gathered from the conversation below.

API

From the highest level perspective, if we're following the Sublime model, we'll want to define three disparate APIs that talk to each other, along with one separate.

Name Description Reference
Tool API Entrypoint for our tool(s)
Key Binding API Custom hotkeys .sublime-keymap
Menu API Custom menus .sublime-menu
Theme API A CSS file (basically) Color Scheme

A package does not necessarily need a tool to be considered a package, examples include themes, hotkey reassignments (perhaps for some particular workflow) or custom menus, but they will need to use at least one of these before being added into the channel.

Tool API

The interface for the tool itself.

Key Binding API

I want to enable tool authors to include hotkeys, but we can't use native Maya functionality here, because it (1) relies on a single file (so no overriding) and (2) the file is automatically written to at shutdown (by default) which makes it brittle.

We need something robust. Something that takes precedence over whatever Maya already does, something we control.

So my idea was to install QShortcuts and manage them ourselves.

That way we are called first, and can choose to pass it on to Maya if we wanted to.

Menu API

Similar to the Key Binding API, I'd like this to also exist isolated and separate from Maya's internal menu API. Simply because it is terrible in that it loads them dynamically and without any pre-defined order or timing, making it difficult to make changes to.

So my idea was to install QMenus and manage them ourselves.

Theme API

We could package a simple CSS file to be activated/deactivated at will. An interesting aspect of Sublime is that it supports themes from another well known Editor - TextMate. That way, all existing themes developed for that works for Sublime which gives it an starting point for available themes.

We could potentially do that too, and if not, define some scheme that others may eventually adopt from us.

@morganloomis
Copy link

morganloomis commented Oct 6, 2016

When you say plugins should have no dependencies, do plugins == tools?
I have a simple dependency for most tools, there's one utilities script which aggregates reusable code, and most other tools import it. Would plugins absolutely need to be one script, or could a tool consist of multiple files? What about including things like icons?

@mottosso
Copy link
Member Author

mottosso commented Oct 7, 2016

do plugins == tools

Excellent start, we'll need a strong definition of what we're really creating. Yes, when I said plug-in, I meant the tool that we are distributing. Should we refer to these as "tools" henceforth?

Maybe tool is too specific. I'm also picturing some tools to really be themes, or just remapped keyboard shortcuts. In the spirit of Sublime, how about "package"?

I have a simple dependency for most tools, there's one utilities script which aggregates reusable code, and most other tools import it.

This makes sense for a lot of things, it just makes it impossible to distribute without some dependency management of sorts and I don't think we should get into that. It's just too complex.

In this case, I'd imagine you extracting the dependent parts of your utility file, and ship it with the tool.

Would plugins absolutely need to be one script, or could a tool consist of multiple files? What about including things like icons?

In Sublime, a package is the whole Git repository which can include a Python package, so this should be fine here as well.

package/
  mytool/
    __init__.py
    util.py
  icon.png
  README.md

@mottosso
Copy link
Member Author

mottosso commented Oct 7, 2016

Oh and a version. Every package will need a unique version. Sublime goes for http://semver.org and I think we should too. In addition, it listens for when a new GitHub "release" is made and considers that an update of your package.

Requirements

@mottosso
Copy link
Member Author

mottosso commented Oct 7, 2016

So to throw something out there in terms of options, here's what we could do, if we went full-Sublime replica.

Class Description
ViewportPackage Runs within the context of the viewport, passes OpenGL state, access to interactive events like when something is selected, created etc. Anything from MSceneMessage
CommandPackage Runs within the context of Maya the software/engine, access to the current selection, creates new command accessible via MEL and cmds.
WindowPackage Runs within the context of the Maya Window and QApplication, access to general events such as window moved, resized etc.

Example

from maya_package import ViewportPackage, CommandPackage, WindowPackage

class SetDefaults(CommandPackage):
  def run(self, selection):
    for node in selection:
      for attr in cmds.listAttr(node):
        default = cmds.addAttr("node + "." + attr, query=True, defaultValue=True)
        cmds.setAttr(node + "." + attr, default)

@mottosso
Copy link
Member Author

mottosso commented Oct 7, 2016

And here's some inspiration on how to guide users through the creation of a package.

@morganloomis
Copy link

How about shelves and shelf buttons? That's a pretty common front-end for tools in maya. Also possibly marking menus or context menus? I don't know if that falls into the same category as the rest of these.

Not familiar with QShortcuts or QMenu, so might just be my inexperience speaking but as a user I would potentially find it confusing for hotkeys to be handled differently from what I was used to in default maya. If I looked in the hotkey editor or exported hotkeys, would that include the ones set by the package?

@mottosso
Copy link
Member Author

mottosso commented Oct 8, 2016

If I looked in the hotkey editor or exported hotkeys, would that include the ones set by the package?

They would not. And not because I think it's better in any way - I agree with you, it should be integrated better - but because I think it will simply be impossible or impractical to keep up with.

It's important we have this discussion - maybe I'm wrong - because if we do go down this route, otehrs will wonder the same thing. So we'll need a strong conceptual foundation to what I believe to be the strongest technical foundation.

The problems are (1) hotkeys in Maya are distributed between no less than 3 separate MEL files that are (2) updated simultaneously and independently by each running Maya session that are (3) not editable at run-time.

File Purpose
userHotkeys.mel key-combination + MEL/Python script[1]
userNamedCommands.mel contains all commands that have hotkeys assigned to them
userRunTimeCommands.mel script + MEL command

[1]: Script differs from "command" which is a built-in member of cmds and directly accessible via MEL as a reserved keyword.

If we can find a way to eliminate these 3 problems, and still integrate into the native hotkey system/ui, we're done. And using QShortcut is one way of overcoming these problems, at the expense of externalising ourselves from the native hotkey editor.

For example, I think it's needlessly complex having three files involved in what should only need one, and Sublime handles this well.

{
  "key combination": "command and extras"
}

In addition, it handles cascading groups, such that you can have one root-level json file with hotkeys be overridden by another with "higher precedence". That's how our tools will take precedence over native hotkeys, and how other "more important" tools take precedence over each other. There is simply no way this can happen via the built-in mechanism and it's going to be important to user experience.

@BigRoy
Copy link
Contributor

BigRoy commented Oct 12, 2016

Every package will need a unique version. Sublime goes for http://semver.org and I think we should too.

+1. Totally agree.

How about shelves and shelf buttons? That's a pretty common front-end for tools in maya. Also possibly marking menus or context menus? I don't know if that falls into the same category as the rest of these.

I think this is something we might be able to get to later. When the scripts are additionally able to "register a menu" eventually. Not that we shouldn't think about it now, but implementation could come later.


The most important bit is deciding on how scripts register functionality. Once that has an abstract generalized interface we can start adding extra features that could be registered. I imagine a new tool to come with a file that registers the features (maybe even with default shortcuts).

In the simplest sense:

import maya_control.api

plugin = maya_control.api.Plugin()
plugin.register_shortcut("key", "description", "command")
plugin.register_shortcut("key2", "description", "command2")
plugin.register_command("my_script", method)
plugin.register_menu("tool_menu", menu_builder)
plugin.register_shelf("tool_shelf", shelf_builder)

maya_control.api.register_plugin(plugin)

The things that could be "registered" and as such provided as features could be expanded upon. With shortcuts (or menus) abstracted away like this than maya_control could also start adding support for enabling/disabling menus, shortcuts, commands per package.

Internally the package would be self-sufficient if we want to avoid needing a custom dependency management system (which is a very involved system to get into).

Whether what's being registered is subclassed from "packages" maya_control offers depends on how involved the features are that will be implemented.

I feel we should get a prototype up and running and go from there? Basically get a feeling of what we'd need.

@mottosso
Copy link
Member Author

Here's an example of how QShortcut can be used to replace native hotkey functionality.

from Qt import QtCore, QtGui, QtWidgets

def shortcut(sequence, callable):
    # Get window, once
    shortcut.parent = getattr(shortcut, "parent", None) or next(
        o for o in QtWidgets.qApp.topLevelWidgets()
        if o.objectName() == "MayaWindow"
    )

    sequence = QtGui.QKeySequence(sequence)
    return QtWidgets.QShortcut(sequence, shortcut.parent, callable)

def callback():
  print("Called back")

key = shortcut("ctrl+c", callback)

# Disable it like so
# key.setEnabled(False)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants