Skip to content

Instantly share code, notes, and snippets.

@yamahigashi
Created July 8, 2021 08:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yamahigashi/c93938b0f8fd578cf35ea0d9748a9804 to your computer and use it in GitHub Desktop.
Save yamahigashi/c93938b0f8fd578cf35ea0d9748a9804 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
###############################################################################
import textwrap
import functools
import maya.cmds as cmds
import maya.mel as mel
from logging import ( # noqa:F401 pylint: disable=unused-import, wrong-import-order
StreamHandler,
getLogger,
WARN,
DEBUG,
INFO
)
if False: # pylint: disable=using-constant-test, wrong-import-order
# For type annotation
from typing import ( # NOQA: F401 pylint: disable=unused-import
Optional,
Dict,
List,
Tuple,
Pattern,
Callable,
Any,
Text,
Generator,
Union
)
from pathlib import Path # NOQA: F401, F811 pylint: disable=unused-import,reimported
from types import ModuleType # NOQA: F401 pylint: disable=unused-import
from six.moves import reload_module as reload # NOQA: F401 pylint: disable=unused-import
handler = StreamHandler()
handler.setLevel(DEBUG)
logger = getLogger(__name__)
logger.setLevel(INFO)
logger.addHandler(handler)
logger.propagate = False
##############################################################################
def get_unique_window_id(candidate):
# type: (Text) -> Text
"""Returns unique id for window it may contain sequencial number."""
def _is_window_exists(query):
return cmds.window(query, q=True, exists=True)
num = 0
query = candidate
while _is_window_exists(query):
query = "{}{}".format(candidate, num)
num += 1
return query
def open_limittransforms_view():
# type: () -> None
try:
# spawn GUI elements, window, panel and layout
window_id = get_unique_window_id("LimitTransformView")
cmds.window()
window = cmds.window(
window_id,
title='Limit Transforms View',
sizeable=True,
topLeftCorner=[200, 200],
)
layout = cmds.formLayout()
cmds.setParent('..')
cmds.window(
window_id,
edit=True
)
except RuntimeError:
raise
_fill_view_with_layout(layout)
cmds.showWindow(window)
def limit_selection_with_current_value(axis, is_min, *arg, **kwargs):
# type: (Text, bool, Optional[List], Optional[Dict]) -> None
for sel in cmds.ls(sl=True, type="transform"):
value = cmds.getAttr("{}.{}".format(sel, axis))
__limit(sel, axis, is_min, value)
redraw_ui()
def redraw_ui():
# TODO:
# redraw the attribute editor
sel = cmds.ls(sl=True)
if sel:
mel.eval("""showEditorExact "{}";""".format(sel[0]))
def __limit(obj, axis, is_min, value):
# type: (Text, Text, bool, float) -> None
"""Do transformLimits with given arguments.
if value is None, then clear limits.
"""
# ------------------------------------
values = [-1., 1.]
opts = {
"enableRotationX": axis == "rx",
"enableRotationY": axis == "ry",
"enableRotationZ": axis == "rz",
"enableScaleX": axis == "sx",
"enableScaleY": axis == "sy",
"enableScaleZ": axis == "sz",
"enableTranslationX": axis == "tx",
"enableTranslationY": axis == "ty",
"enableTranslationZ": axis == "tz",
}
current_enabled = cmds.transformLimits(obj, q=True, **opts)
opts = {
"rotationX": axis == "rx",
"rotationY": axis == "ry",
"rotationZ": axis == "rz",
"scaleX": axis == "sx",
"scaleY": axis == "sy",
"scaleZ": axis == "sz",
"translationX": axis == "tx",
"translationY": axis == "ty",
"translationZ": axis == "tz",
}
current_value = cmds.transformLimits(obj, q=True, **opts)
if is_min:
enabled = [value is not None, current_enabled[1]]
values = [value, current_value[1]]
else:
enabled = [current_enabled[0], value is not None]
values = [current_value[0], value]
# ------------------------------------
if value is not None:
if axis == "rx":
cmds.transformLimits(obj, rx=values, erx=enabled)
elif axis == "ry":
cmds.transformLimits(obj, ry=values, ery=enabled)
elif axis == "rz":
cmds.transformLimits(obj, rz=values, erz=enabled)
elif axis == "sx":
cmds.transformLimits(obj, sx=values, esx=enabled)
elif axis == "sy":
cmds.transformLimits(obj, sy=values, esy=enabled)
elif axis == "sz":
cmds.transformLimits(obj, sz=values, esz=enabled)
elif axis == "tx":
cmds.transformLimits(obj, tx=values, etx=enabled)
elif axis == "ty":
cmds.transformLimits(obj, ty=values, ety=enabled)
elif axis == "tz":
cmds.transformLimits(obj, tz=values, etz=enabled)
else:
print("error arguments must rx, ry, rz, .... but {}".format(axis))
else:
if axis == "rx":
cmds.transformLimits(obj, erx=enabled)
elif axis == "ry":
cmds.transformLimits(obj, ery=enabled)
elif axis == "rz":
cmds.transformLimits(obj, erz=enabled)
elif axis == "sx":
cmds.transformLimits(obj, esx=enabled)
elif axis == "sy":
cmds.transformLimits(obj, esy=enabled)
elif axis == "sz":
cmds.transformLimits(obj, esz=enabled)
elif axis == "tx":
cmds.transformLimits(obj, etx=enabled)
elif axis == "ty":
cmds.transformLimits(obj, ety=enabled)
elif axis == "tz":
cmds.transformLimits(obj, etz=enabled)
else:
print("error arguments must rx, ry, rz, .... but {}".format(axis))
def toggle(*args, **kwargs):
print(args)
print(kwargs)
pass
def clear(attr, *args, **kwargs):
for axis in ["x", "y", "z"]:
at = "{}{}".format(attr.lower()[0], axis)
for sel in cmds.ls(sl=True, type="transform"):
value = cmds.getAttr("{}.{}".format(sel, at))
__limit(sel, at, True, None)
__limit(sel, at, False, None)
redraw_ui()
def _fill_view_with_layout(layout):
# type: (Text) -> None
cmds.setParent('..')
rows = cmds.rowLayout(numberOfColumns=30)
# cmds.setParent('..')
col = cmds.columnLayout(width=80)
# cmds.text(label="")
cmds.button(label="Toggle", command=toggle)
cmds.text(label="Upper: +")
cmds.text(label="Lower: -")
cmds.setParent('..')
for attribute in ["Rotate", "Trans ", "Scale "]:
cmds.columnLayout(width=100)
cmds.rowLayout(numberOfColumns=2)
cmds.text(label=attribute)
cmds.button(label="clear", command=functools.partial(clear, attribute))
cmds.setParent('..')
for flag in [False, True]:
cmds.rowLayout(numberOfColumns=3)
for axis in ["x", "y", "z"]:
attr = "{}{}".format(attribute.lower()[0], axis)
cmds.button(
label=axis.upper(),
width=22,
height=22,
command=functools.partial(limit_selection_with_current_value, attr, flag)
)
cmds.setParent('..')
cmds.setParent('..')
cmds.formLayout(
layout,
edit=True,
attachForm=[
(rows, 'left', 15),
(rows, 'top', 5),
(rows, 'bottom', 5),
(rows, 'right', 15),
]
)
def _open():
open_limittransforms_view()
if __name__ == "__main__":
_open()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment