Created
July 8, 2021 08:11
-
-
Save yamahigashi/c93938b0f8fd578cf35ea0d9748a9804 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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