I’ll try to keep it short, and hopefully it would not be confusing (though it probably will be), and help you get a clearer picture of what’s going on.
Question 1 - I guess you’ve just copied code, and methods are left in global scope (no indentation), effectively making them functions - by saying:
It was kinda assumed that you would put them inside ‘CustomContextCmd’ class, where you have placed ‘appendSyntax’ method (that’s how you override methods), which means ‘self’ would be reference to this class instance, like usual.
So, if you place that code in correct place, then you can create your context:
ctx = cmds.customCommand()
After which you could query and edit flags of your context instance like:
cmds.customCommand(ctx, e=True, m=42)
cmds.customCommand(ctx, q=True, m=True)
And of course, use it:
cmds.setToolTo(ctx)
And you need to create context instance first, prior to accessing it. Not really sure if you could pass flags at instantiation time, or would it make any sense (like, why would you pass anything to ‘move’ tool (which is context); maybe gizmo size, or something, but don’t know; haven’t tried it - might be totally valid…).
But I don’t think that’s the idea of how you should use contexts - rather you should have context accompanied by MEL scripts (named same as your context command, with Properties and Values suffixes; so, ‘customCommandProperties’ and ‘customCommandValues’), which will define how Tool Settings UI (UI that pops up when you double-click ‘move’ context, for example), and its UI elements, will interact with your context (here comes querying and editing context command flags).
*Note: you could put all code of these 2 scripts in one MEL file (‘customCommandProperties.mel’), and it will work same as if ‘customCommandValues.mel’ is created also.
I think main confusion here is that you’re mixing context command and tool command - they are not same thing. Command can (and should) take flags (and tool command is just a command), because you don’t create it, but run it; context command, which actually creates context tool doesn’t really need flags, since when your tool is active, you can access it via above mentioned tool settings (again, perhaps it’s possible/beneficial to pass something, so you could try it - hopefully, you’ll get enough info after reading this).
**And all arguments parsing logic in your code is in class that you don’t use (read just below).
Question 2 - your code kinda answers it - MPxToolCommand is optional, and in your code (which I’ve noticed later on), you’re not actually using that class at all (could delete entire ‘CutomTool’ class, and won’t make a slightest change) - you must register that command also, along with registering context command (and deregister, of course) in ‘initializePlugin’ function (look code below) - using ‘registerCommand()’ and ‘registerContextCommand()’ methods respectively.
MPxToolCommand have methods that should be used from context tool (like for undo functionality, etc.), otherwise, it would be regular MPxCommand.
If you need tool command, then, like I said, you need to register it, so you need to give it a name, which you would register and use to run it. And you could use flags with it.
Without further delay, here’s some (based on yours) code that will register both context and tool commands, and you could try mixing it up, play with it, and perhaps get what you want:
import maya.api.OpenMaya as om
import maya.api.OpenMayaUI as omui
# flag definition
kMeshFlag = "-m"
kMeshLongFlag = "-mesh"
# tell maya plugin produces and need to be passed, maya api 2.0
def maya_useNewAPI():
pass
class CutomTool(omui.MPxToolCommand):
""" ."""
COMMAND_NAME = 'cutomTool'
mesh = None
def __init__(self):
super().__init__()
@classmethod
def syntaxCreator(cls):
""" ."""
syntax = om.MSyntax()
# (short name, long name, argument data type)
syntax.addFlag(kMeshFlag, kMeshLongFlag, om.MSyntax.kString)
return syntax
def argumentParser(self, argList):
""" ."""
syntax = self.syntax()
parsedArguments = om.MArgParser(syntax, argList)
if parsedArguments.isFlagSet(kMeshFlag):
self.mesh = parsedArguments.flagArgumentString(kMeshFlag, 0)
if parsedArguments.isFlagSet(kMeshLongFlag):
self.mesh = parsedArguments.flagArgumentString(kMeshLongFlag, 0)
def doIt(self, argList):
""" ."""
self.argumentParser(argList)
if self.mesh:
self.redoIt()
def isUndoable(self):
""" ."""
return True
# action to undo operation
def undoIt(self):
""" ."""
print ("undo")
def redoIt(self):
""" ."""
print ("redo")
def finalize(self):
""" ."""
command = om.MArgList()
command.addArg(om.MString(kMeshFlag))
command.addArg(self.mesh)
try:
omui.MPxToolCommand.doFinalize(self, command)
except Exception:
pass
@classmethod
def creator(cls):
""" ."""
return cls()
class CustomContext(omui.MPxContext):
""" ."""
TITLE = "Title"
HELP_TEXT = "Help Text"
def __init__(self):
super().__init__()
self.setTitleString(CustomContext.TITLE)
def helpStateHasChanged(self, event):
self.setHelpString(CustomContext.HELP_TEXT)
def toolOnSetup(self,event):
om.MGlobal.selectCommand(om.MSelectionList()) # select nothing, to record undo
self.reset_context()
def toolOffCleanup(self):
self.reset_context()
def doPress(self, event, draw_manager, frame_context):
print ("do press")
def completeAction(self):
print ("complete action")
def deleteAction(self):
print ("undo")
def abortAction(self):
print ("abort")
def reset_context(self):
print ("reset")
class CustomContextCmd(omui.MPxContextCommand):
""" ."""
COMMAND_NAME = "testTA" # used as mel command to create context
def __init__(self):
super().__init__()
# required for maya to get instance of context
def makeObj(self):
return CustomContext() # return ribbon spline ctx
@classmethod
def creator(cls):
return CustomContextCmd() # return ribbon spline ctx cmd
def appendSyntax(self):
""" ."""
syntax = self.syntax()
syntax.addFlag(kMeshFlag, kMeshLongFlag, om.MSyntax.kLong)
def doEditFlags(self):
""" ."""
argParser = self.parser()
if argParser.isFlagSet(kMeshFlag):
mesh_flag = argParser.flagArgumentInt(kMeshFlag, 0)
# do something meaningful when in edit mode
self.mesh_flag = mesh_flag # like setting a dummy attribute..
print(f'===>>> Editing flag with value: {mesh_flag} <<<===')
def doQueryFlags(self):
""" ."""
argParser = self.parser()
if argParser.isFlagSet(kMeshFlag):
# get something when in query mode, and call setResult() method with argument of what querying this flag should return
if hasattr(self, 'mesh_flag'): # just a check if attribute exists, since we've created it on the fly for this demo, in first edit flag call
print(f'===>>> Querying flag {kMeshLongFlag}: {self.mesh_flag} <<<===')
self.setResult(self.mesh_flag) # setting result to dummy value we stored when editing flag
def initializePlugin(plugin):
plugin_fn = om.MFnPlugin(plugin)
try:
plugin_fn.registerCommand(CutomTool.COMMAND_NAME, CutomTool.creator, CutomTool.syntaxCreator)
plugin_fn.registerContextCommand(CustomContextCmd.COMMAND_NAME, CustomContextCmd.creator)
except:
om.MGlobal.displayError(f"Failed to register context command: {CustomContextCmd.COMMAND_NAME}")
def uninitializePlugin(plugin):
plugin_fn = om.MFnPlugin(plugin)
try:
plugin_fn.deregisterContextCommand(CustomContextCmd.COMMAND_NAME)
plugin_fn.deregisterCommand(CutomTool.COMMAND_NAME)
except:
om.MGlobal.displayError(f"Failed to deregister context command: {CustomContextCmd.COMMAND_NAME}")
I’ve changed name of context command to ‘testTA’, so, either create it with ctx = cmds.testTA()
, or rename it (‘customCommand’ was too generic, and was overriding something).
Also, I left the name of class ‘CutomTool’, though I think it’s a typo.
You create context tool as mentioned above. And you can run your command with:
cmds.cutomTool()
cmds.cutomTool(m='blah')
So, these are two distinct things: ‘customCommand’ context command, and ‘cutomTool’ command. And you don’t have to create context first, in order to run command.
P.S. For steps 1 and 2 - maybe that’s not the best approach, to pass arguments, but you should utilize context’s tool settings (explained above) for producing different behaviour (like, I think, it’s meant to be used).
Or you may try to pass arguments to tool command, and that tool command creates context, and sets what needs to be set, etc…