Skip to content

Commit 8431607

Browse files
authored
Merge pull request #128 from GenEugene/new-transformation-tools
Transformation tools
2 parents ab4a7d8 + b328a29 commit 8431607

3 files changed

Lines changed: 227 additions & 8 deletions

File tree

GETOOLS_SOURCE/modules/GeneralWindow.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
from .. import Settings
2828
from ..modules import Options
29+
from ..modules import Transformations
2930
from ..modules import Tools
3031
from ..modules import Rigging
3132
from ..modules import Overlappy
@@ -49,14 +50,15 @@
4950

5051

5152
class GeneralWindow:
52-
_version = "v1.5.2"
53+
_version = "v1.6.0"
5354
_name = "GETools"
5455
_title = _name + " " + _version
5556

5657
def __init__(self):
5758
self.optionsPlugin = Options.PluginVariables()
5859
self.optionsPlugin.titleGeneral = GeneralWindow._title
5960

61+
self.frameTransformations = None
6062
self.frameTools = None
6163
self.frameRigging = None
6264
self.frameOverlappy = None
@@ -74,6 +76,7 @@ def CreateUI(self):
7476

7577
layoutScroll = cmds.scrollLayout(parent = generalWindow, width = Settings.windowWidthOffset)
7678

79+
self.LayoutTransformations(parentLayout = layoutScroll)
7780
self.LayoutTools(parentLayout = layoutScroll)
7881
self.LayoutRigging(parentLayout = layoutScroll)
7982
self.LayoutOverlappy(parentLayout = layoutScroll)
@@ -432,24 +435,27 @@ def LayoutMenuOptions(self):
432435
cmds.menuItem(label = "Delete", command = partial(Install.ToShelf_MotionTrailDelete, self.optionsPlugin.directory), image = Icons.minus)
433436
cmds.setParent('..', menu = True)
434437

438+
def LayoutTransformations(self, parentLayout):
439+
self.frameTransformations = cmds.frameLayout(parent = parentLayout, label = "1. " + Transformations.Transformations._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
440+
Transformations.Transformations(self.optionsPlugin).UICreate(self.frameTransformations)
435441
def LayoutTools(self, parentLayout):
436-
self.frameTools = cmds.frameLayout(parent = parentLayout, label = "1. " + Tools.Tools._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
442+
self.frameTools = cmds.frameLayout(parent = parentLayout, label = "2. " + Tools.Tools._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
437443
Tools.Tools(self.optionsPlugin).UICreate(self.frameTools)
438444
def LayoutRigging(self, parentLayout):
439-
self.frameRigging = cmds.frameLayout(parent = parentLayout, label = "2. " + Rigging.Rigging._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
445+
self.frameRigging = cmds.frameLayout(parent = parentLayout, label = "3. " + Rigging.Rigging._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
440446
Rigging.Rigging(self.optionsPlugin).UICreate(self.frameRigging)
441447
def LayoutOverlappy(self, parentLayout):
442-
self.frameOverlappy = cmds.frameLayout(parent = parentLayout, label = "3. " + Overlappy.Overlappy._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
448+
self.frameOverlappy = cmds.frameLayout(parent = parentLayout, label = "4. " + Overlappy.Overlappy._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
443449
Overlappy.Overlappy(self.optionsPlugin).UICreate(self.frameOverlappy)
444450
def LayoutCenterOfMass(self, parentLayout):
445-
self.frameCenterOfMass = cmds.frameLayout(parent = parentLayout, label = "4. " + CenterOfMass.CenterOfMass._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
451+
self.frameCenterOfMass = cmds.frameLayout(parent = parentLayout, label = "5. " + CenterOfMass.CenterOfMass._title, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
446452
CenterOfMass.CenterOfMass(self.optionsPlugin).UICreate(self.frameCenterOfMass)
447453
def LayoutMotionTrail(self, parentLayout):
448454
versionMT = "v1.0" # TODO move to Motion Trail class when possible
449455
nameMT = "MOTION TRAIL"
450456
titleMT = nameMT + " " + versionMT
451457

452-
self.frameMotionTrail = cmds.frameLayout(parent = parentLayout, label = "5. " + titleMT, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
458+
self.frameMotionTrail = cmds.frameLayout(parent = parentLayout, label = "6. " + titleMT, collapsable = True, backgroundColor = Settings.frames1Color, width = Settings.windowWidth, marginWidth = Settings.marginWidth, marginHeight = Settings.marginHeight)
453459

454460
countOffsets = 3
455461
cmds.gridLayout(parent = self.frameMotionTrail, numberOfColumns = countOffsets, cellWidth = Settings.windowWidthMargin / countOffsets, cellHeight = Settings.lineHeight)
@@ -486,6 +492,8 @@ def WindowDelete(self, *args):
486492
else:
487493
print("No Window")
488494
def FramesCollapse(self, value, *args): # TODO collapse function for sub frames
495+
if self.frameTransformations is not None:
496+
cmds.frameLayout(self.frameTransformations, edit = True, collapse = value)
489497
if self.frameTools is not None:
490498
cmds.frameLayout(self.frameTools, edit = True, collapse = value)
491499
if self.frameRigging is not None:
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# GETOOLS is under the terms of the MIT License
2+
# Copyright (c) 2018-2024 Eugene Gataulin (GenEugene). All Rights Reserved.
3+
4+
# Permission is hereby granted, free of charge, to any person obtaining a copy
5+
# of this software and associated documentation files (the "Software"), to deal
6+
# in the Software without restriction, including without limitation the rights
7+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
# copies of the Software, and to permit persons to whom the Software is
9+
# furnished to do so, subject to the following conditions:
10+
11+
# The above copyright notice and this permission notice shall be included in all
12+
# copies or substantial portions of the Software.
13+
14+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
21+
# Author: Eugene Gataulin tek942@gmail.com https://www.linkedin.com/in/geneugene https://discord.gg/heMxJhTqCz
22+
# Source code: https://github.com/GenEugene/GETools or https://app.gumroad.com/geneugene
23+
24+
import maya.cmds as cmds
25+
from functools import partial
26+
27+
from .. import Settings
28+
from ..utils import Colors
29+
# from ..utils import Selector
30+
# from ..values import Enums
31+
32+
33+
class TransformationsAnnotations:
34+
space = "WORLD SPACE uses global axes orientations.\nLOCAL SPACE uses parent space, useful when selected object is a child of other object.\nOBJECT SPACE uses selected objects' axes and move accordingly arrows."
35+
relative = "Current position used as a start point resulting move addition each step.\nDeactivate to use absolute mode to set specific coordinates."
36+
preserveChildPosition = "Child object will stay on the same position while selected object will be moved.\nVery useful when you need to tweak object's position in the middle of hierarchy."
37+
pivot = "Move pivot of selected objects instead of moving objects transform nodes"
38+
multiplier = "Extra multiplier for DIRECTION and DISTANCE values."
39+
40+
editPivot = "Toggle pivot editing for selected objects.\nThe same action as 'D' hotkey on keyboard."
41+
pivotOn = "Show pivot attributes in channel box"
42+
pivotOff = "Hide pivot attributes in channel box"
43+
44+
_negativePositive = "-+ symbols mean negative and positive directions"
45+
direction = "XYZ values for directional movement"
46+
moveDirection = "Apply XYZ movement with direction values.\n{0}.".format(_negativePositive)
47+
distance = "Distance value for separate axes movement"
48+
moveDistance = "Apply axis movement using distance.\n{0}.".format(_negativePositive)
49+
50+
class Transformations:
51+
_version = "v1.0"
52+
_name = "TRANSFORMATIONS"
53+
_title = _name + " " + _version
54+
55+
def __init__(self, options):
56+
self.optionsPlugin = options
57+
### Check Maya version to avoid cycle import, Maya 2020 and older can't use cycle import
58+
if cmds.about(version = True) in ["2022", "2023", "2024", "2025"]:
59+
from . import Options
60+
if isinstance(options, Options.PluginVariables):
61+
self.optionsPlugin = options
62+
63+
### UI elements with values
64+
self.radioButtonGrpSpace = None
65+
self.checkBoxRelative = None
66+
self.checkBoxPreserveChildPosition = None
67+
self.checkBoxPivot = None
68+
self.floatFieldMultiplier = None
69+
self.floatFieldGrpDirection = None
70+
self.floatFieldDistance = None
71+
def UICreate(self, layoutMain):
72+
self.UILayoutLocators(layoutMain)
73+
cmds.separator(parent = layoutMain, height = Settings.separatorHeight, style = "none")
74+
def UILayoutLocators(self, layoutMain):
75+
cmds.frameLayout(parent = layoutMain, label = Settings.frames2Prefix + "MOVE", collapsable = True, backgroundColor = Settings.frames2Color, highlightColor = Colors.green100, marginWidth = 0, marginHeight = 0, borderVisible = True)
76+
layoutColumn = cmds.columnLayout(adjustableColumn = True)
77+
78+
self.radioButtonGrpSpace = cmds.radioButtonGrp(parent = layoutColumn, label = "Space: ", labelArray3 = ["World", "Local", "Object"], select = 1, numberOfRadioButtons = 3, columnWidth4 = (60, 50, 50, 50), columnAlign = [(1, "right"), (2, "center"), (3, "center"), (4, "center")], height = Settings.lineHeight, annotation = TransformationsAnnotations.space)
79+
self.radioButtonGrpSpace = self.radioButtonGrpSpace.replace(Settings.windowName + "|", "") # HACK fix for docked window only. Don't know how to avoid issue
80+
81+
cmds.rowLayout(parent = layoutColumn, numberOfColumns = 3, columnWidth3 = (70, 150, 50), columnAlign = [(1, "center"), (2, "center"), (3, "center")], columnAttach = [(1, "both", 0), (2, "both", 0), (3, "both", 0)], height = Settings.lineHeight)
82+
self.checkBoxRelative = cmds.checkBox(label = "Relative", value = True, annotation = TransformationsAnnotations.relative)
83+
self.checkBoxPreserveChildPosition = cmds.checkBox(label = "Preserve Child Position", value = False, annotation = TransformationsAnnotations.preserveChildPosition)
84+
self.checkBoxPivot = cmds.checkBox(label = "Pivot", value = False, annotation = TransformationsAnnotations.pivot)
85+
86+
cmds.rowLayout(parent = layoutColumn, adjustableColumn = 2, numberOfColumns = 5, columnWidth5 = (60, 50, 60, 50, 50), columnAlign = [(1, "right"), (2, "center"), (3, "center"), (4, "center"), (5, "center")], columnAttach = [(1, "both", 0), (2, "both", 0), (3, "both", 0), (4, "both", 0), (5, "both", 0)], height = Settings.lineHeight)
87+
cmds.text(label = "Multiplier: ", annotation = TransformationsAnnotations.multiplier)
88+
self.floatFieldMultiplier = cmds.floatField(value = 1, precision = 3, annotation = TransformationsAnnotations.multiplier)
89+
cmds.popupMenu()
90+
cmds.menuItem(label = "0.001", command = partial(self.SetMultiplier, 0.001))
91+
cmds.menuItem(label = "0.01", command = partial(self.SetMultiplier, 0.01))
92+
cmds.menuItem(label = "0.1", command = partial(self.SetMultiplier, 0.1))
93+
cmds.menuItem(label = "0.2", command = partial(self.SetMultiplier, 0.1))
94+
cmds.menuItem(label = "0.5", command = partial(self.SetMultiplier, 0.5))
95+
cmds.menuItem(divider = True)
96+
cmds.menuItem(label = "1", command = partial(self.SetMultiplier, 1))
97+
cmds.menuItem(divider = True)
98+
cmds.menuItem(label = "1.05", command = partial(self.SetMultiplier, 1.05))
99+
cmds.menuItem(label = "1.1", command = partial(self.SetMultiplier, 1.1))
100+
cmds.menuItem(label = "1.5", command = partial(self.SetMultiplier, 1.5))
101+
cmds.menuItem(divider = True)
102+
cmds.menuItem(label = "2", command = partial(self.SetMultiplier, 2))
103+
cmds.menuItem(label = "3", command = partial(self.SetMultiplier, 3))
104+
cmds.menuItem(label = "4", command = partial(self.SetMultiplier, 4))
105+
cmds.menuItem(label = "5", command = partial(self.SetMultiplier, 5))
106+
cmds.menuItem(divider = True)
107+
cmds.menuItem(label = "10", command = partial(self.SetMultiplier, 10))
108+
cmds.menuItem(label = "100", command = partial(self.SetMultiplier, 100))
109+
cmds.menuItem(label = "1000", command = partial(self.SetMultiplier, 1000))
110+
cmds.button(label = "Edit Pivot", command = cmds.EnterEditModePress, backgroundColor = Colors.yellow10, annotation = TransformationsAnnotations.editPivot)
111+
cmds.button(label = "Pivot On", command = partial(self.SetPivotAttributes, True), backgroundColor = Colors.blackWhite80, annotation = TransformationsAnnotations.pivotOn)
112+
cmds.button(label = "Pivot Off", command = partial(self.SetPivotAttributes, False), backgroundColor = Colors.blackWhite80, annotation = TransformationsAnnotations.pivotOff)
113+
114+
rowLayoutDirection = cmds.rowLayout(parent = layoutColumn, adjustableColumn = 2, numberOfColumns = 2, columnWidth2 = (188, 60), columnAlign = [(1, "right"), (2, "center")], columnAttach = [(1, "both", 0), (2, "both", 0)], height = Settings.lineHeight)
115+
self.floatFieldGrpDirection = cmds.floatFieldGrp(parent = rowLayoutDirection, label = "Direction: ", numberOfFields = 3, columnWidth4 = (60, 40, 40, 40), value = [0, 0, 0, 0], columnAlign = [(1, "right"), (2, "center"), (3, "center"), (4, "center")], annotation = TransformationsAnnotations.direction)
116+
self.floatFieldGrpDirection = self.floatFieldGrpDirection.replace(Settings.windowName + "|", "") # HACK fix for docked window only. Don't know how to avoid issue
117+
cmds.popupMenu()
118+
cmds.menuItem(label = "0, 0, 0", command = partial(self.SetDirection, [0, 0, 0]))
119+
cmds.menuItem(divider = True)
120+
cmds.menuItem(label = "1, 0, 0", command = partial(self.SetDirection, [1, 0, 0]))
121+
cmds.menuItem(label = "0, 1, 0", command = partial(self.SetDirection, [0, 1, 0]))
122+
cmds.menuItem(label = "0, 0, 1", command = partial(self.SetDirection, [0, 0, 1]))
123+
cmds.gridLayout(parent = rowLayoutDirection, numberOfColumns = 2, cellWidth = 44, cellHeight = Settings.lineHeight)
124+
cmds.button(label = "-XYZ", command = partial(self.MoveSelected, 0, True), backgroundColor = Colors.orange10, annotation = TransformationsAnnotations.moveDirection)
125+
cmds.button(label = "+XYZ", command = partial(self.MoveSelected, 0, False), backgroundColor = Colors.orange50, annotation = TransformationsAnnotations.moveDirection)
126+
127+
cmds.rowLayout(parent = layoutColumn, adjustableColumn = 2, numberOfColumns = 3, columnWidth3 = (60, 50, 156), columnAlign = [(1, "right"), (2, "center"), (3, "center")], columnAttach = [(1, "both", 0), (2, "both", 0), (3, "both", 0)], height = Settings.lineHeight)
128+
cmds.text(label = "Distance: ", annotation = TransformationsAnnotations.distance)
129+
self.floatFieldDistance = cmds.floatField(value = 1, precision = 3, annotation = TransformationsAnnotations.distance)
130+
cmds.popupMenu()
131+
cmds.menuItem(label = "0", command = partial(self.SetDistance, 0))
132+
cmds.menuItem(divider = True)
133+
cmds.menuItem(label = "0.01", command = partial(self.SetDistance, 0.01))
134+
cmds.menuItem(label = "0.1", command = partial(self.SetDistance, 0.1))
135+
cmds.menuItem(label = "0.5", command = partial(self.SetDistance, 0.5))
136+
cmds.menuItem(divider = True)
137+
cmds.menuItem(label = "1", command = partial(self.SetDistance, 1))
138+
cmds.menuItem(label = "2", command = partial(self.SetDistance, 2))
139+
cmds.menuItem(label = "3", command = partial(self.SetDistance, 3))
140+
cmds.menuItem(label = "5", command = partial(self.SetDistance, 5))
141+
cmds.menuItem(divider = True)
142+
cmds.menuItem(label = "10", command = partial(self.SetDistance, 10))
143+
cmds.menuItem(label = "100", command = partial(self.SetDistance, 100))
144+
cmds.menuItem(label = "1000", command = partial(self.SetDistance, 1000))
145+
cmds.gridLayout(numberOfColumns = 6, cellWidth = 26, cellHeight = Settings.lineHeight)
146+
cmds.button(label = "-X", command = partial(self.MoveSelected, 1, True), backgroundColor = Colors.red10, annotation = TransformationsAnnotations.moveDistance)
147+
cmds.button(label = "+X", command = partial(self.MoveSelected, 1, False), backgroundColor = Colors.red50, annotation = TransformationsAnnotations.moveDistance)
148+
cmds.button(label = "-Y", command = partial(self.MoveSelected, 2, True), backgroundColor = Colors.green10, annotation = TransformationsAnnotations.moveDistance)
149+
cmds.button(label = "+Y", command = partial(self.MoveSelected, 2, False), backgroundColor = Colors.green50, annotation = TransformationsAnnotations.moveDistance)
150+
cmds.button(label = "-Z", command = partial(self.MoveSelected, 3, True), backgroundColor = Colors.blue10, annotation = TransformationsAnnotations.moveDistance)
151+
cmds.button(label = "+Z", command = partial(self.MoveSelected, 3, False), backgroundColor = Colors.blue50, annotation = TransformationsAnnotations.moveDistance)
152+
153+
def SetMultiplier(self, value, *args):
154+
cmds.floatField(self.floatFieldMultiplier, edit = True, value = value)
155+
def SetDirection(self, value, *args):
156+
cmds.floatFieldGrp(self.floatFieldGrpDirection, edit = True, value = [value[0], value[1], value[2], 0])
157+
def SetDistance(self, value, *args):
158+
cmds.floatField(self.floatFieldDistance, edit = True, value = value)
159+
def SetPivotAttributes(self, value, *args):
160+
selected = cmds.ls(selection = True)
161+
for i in range(len(selected)):
162+
cmds.setAttr(selected[i] + ".rotatePivotX", channelBox = value)
163+
cmds.setAttr(selected[i] + ".rotatePivotY", channelBox = value)
164+
cmds.setAttr(selected[i] + ".rotatePivotZ", channelBox = value)
165+
cmds.setAttr(selected[i] + ".scalePivotX", channelBox = value)
166+
cmds.setAttr(selected[i] + ".scalePivotY", channelBox = value)
167+
cmds.setAttr(selected[i] + ".scalePivotZ", channelBox = value)
168+
169+
def MoveSelected(self, axis, reverse=False, *args):
170+
space = cmds.radioButtonGrp(self.radioButtonGrpSpace, query = True, select = True)
171+
isWorldSpace = space == 1
172+
isLocalSpace = space == 2
173+
isObjectSpace = space == 3
174+
175+
relative = cmds.checkBox(self.checkBoxRelative, query = True, value = True)
176+
preserveChildPosition = cmds.checkBox(self.checkBoxPreserveChildPosition, query = True, value = True)
177+
pivot = cmds.checkBox(self.checkBoxPivot, query = True, value = True)
178+
179+
direction = [0, 0, 0]
180+
if axis == 0:
181+
direction = cmds.floatFieldGrp(self.floatFieldGrpDirection, query = True, value = True)
182+
else:
183+
distance = cmds.floatField(self.floatFieldDistance, query = True, value = True)
184+
if axis == 1:
185+
direction = [distance, 0, 0]
186+
if axis == 2:
187+
direction = [0, distance, 0]
188+
if axis == 3:
189+
direction = [0, 0, distance]
190+
191+
multiplier = cmds.floatField(self.floatFieldMultiplier, query = True, value = True)
192+
multiplier = multiplier * (-1 if reverse else 1)
193+
direction[0] = direction[0] * multiplier
194+
direction[1] = direction[1] * multiplier
195+
direction[2] = direction[2] * multiplier
196+
197+
selected = cmds.ls(selection = True)
198+
selectedFinal = []
199+
if (pivot):
200+
for i in range (len(selected)):
201+
selectedFinal.append(selected[i] + ".scalePivot")
202+
selectedFinal.append(selected[i] + ".rotatePivot")
203+
else:
204+
selectedFinal = selected;
205+
206+
cmds.move(direction[0], direction[1], direction[2], selectedFinal, worldSpace = isWorldSpace, objectSpace = isObjectSpace, localSpace = isLocalSpace, relative = relative, preserveChildPosition = preserveChildPosition)
207+

changelog.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
GETools changelog
22

3+
v1.6.0 | 09.12.2024
4+
- [TRANSFORMATIONS] added new tool to move objects.
5+
- [UI] changed list order numbers for main panels. TRANSFORMATION tools now stays in 1 position.
6+
37
v1.5.2 | 05.12.2024
4-
- added dates to changelog and bring changelog from legacy Overlappy repository
5-
- added fresh PNG demo collage with all GETools panels
8+
- added dates to changelog and bring changelog from legacy Overlappy repository.
9+
- added fresh PNG demo collage with all GETools panels.
610

711
v1.5.1 | 03.12.2024
812
- [UI] added visual separation with borders to panels.

0 commit comments

Comments
 (0)