timeSliderをスケールしたいんだわ
と相談がありまして。
詳しく聞くと
- マウスのスクロールでスケールしたい
- 現在のフレームを中心にスケールしたい
という感じでした。
もう少し詳しく考えると
- どんなに広げても、start/endFrameがmax
- どんなに小さくしても今のフレーム+前後1fずつがmin
ですかね。
タイムレンジのスケール自体はまぁきっと問題ないとして、
スクロールをどこで検知させるかですね。
適当なQtWidgetsつくってその上でイベント拾ってしまうのが簡単かなぁ
※ほんとはタイムスライダー上でスクロールのイベント拾えれば良いのですが、ちょっと探しても出てこないので。
実装
import maya.cmds as cmds
from PySide2 import QtWidgets,QtGui,QtCore
import math
objectName = "timeSliderScale"
def resetTimeSlider(scaledStart,scaledEnd):
startLimit = cmds.playbackOptions(q = True, animationStartTime =True)
endLimit = cmds.playbackOptions(q = True, animationEndTime=True)
curStartTime = cmds.playbackOptions(q = True, min =True)
curEndTime = cmds.playbackOptions(q = True, max =True)
if scaledStart == None or scaledEnd == None:
cmds.playbackOptions(min = startLimit, max = endLimit)
return curStartTime,curEndTime
elif curStartTime == startLimit and curEndTime == endLimit:
cmds.playbackOptions(min = scaledStart, max = scaledEnd)
return scaledStart,scaledEnd
else:
cmds.playbackOptions(min = startLimit, max = endLimit)
return curStartTime,curEndTime
def scaleTimeSlider(wheelDelta):
currentTime = cmds.currentTime(q = True)
startLimit = cmds.playbackOptions(q = True, animationStartTime =True)
endLimit = cmds.playbackOptions(q = True, animationEndTime=True)
newStartTime = cmds.playbackOptions(q = True, min =True)
newEndTime = cmds.playbackOptions(q = True, max =True)
startSideRange = (currentTime - newStartTime)
endSideRange = (newEndTime - currentTime)
scaleFactor = abs(wheelDelta) * 0.01
if wheelDelta > 0:
newStartTime = math.floor(currentTime - startSideRange * scaleFactor)
newEndTime = math.ceil(currentTime + endSideRange * scaleFactor)
else:
newStartTime = math.floor(currentTime - startSideRange / scaleFactor)
newEndTime = math.ceil(currentTime + endSideRange / scaleFactor)
if newStartTime == currentTime:
newStartTime = currentTime - 1
if newEndTime == currentTime:
newEndTime = newEndTime + 1
newStartTime = max(int(newStartTime),startLimit)
newEndTime = min(int(newEndTime),endLimit)
cmds.playbackOptions(min = newStartTime, max = newEndTime)
return newStartTime, newEndTime
def scaleSlideTimeSlider(scaleValue,newStartTime,newEndTime):
currentTime = cmds.currentTime(q = True)
startLimit = cmds.playbackOptions(q = True, animationStartTime =True)
endLimit = cmds.playbackOptions(q = True, animationEndTime=True)
startSideRange = (currentTime - newStartTime)
endSideRange = (newEndTime - currentTime)
scaleFactor = abs(120) * 0.01
if scaleValue == 0:
return newStartTime, newEndTime
elif scaleValue < 0:
newStartTime = math.floor(currentTime - startSideRange * scaleFactor)
newEndTime = math.ceil(currentTime + endSideRange * scaleFactor)
else:
newStartTime = math.floor(currentTime - startSideRange / scaleFactor)
newEndTime = math.ceil(currentTime + endSideRange / scaleFactor)
if newStartTime == currentTime or newStartTime > currentTime:
newStartTime = currentTime - 1
if newEndTime == currentTime or newEndTime < currentTime:
newEndTime = newEndTime + 1
newStartTime = max(int(newStartTime),startLimit)
newEndTime = min(int(newEndTime),endLimit)
cmds.playbackOptions(min = newStartTime, max = newEndTime)
return newStartTime, newEndTime
##-----------------------------------------------------------------
def getTopLevelWidget(name):
for widget in QtWidgets.QApplication.topLevelWidgets():
if widget.objectName() == name:
return widget
return None
def windowCheck(object,parent,arrowMulti = False):
if arrowMulti:
allChildrenName = []
renameObject = str(object)
for child in parent.children():
allChildrenName.append(child.objectName())
i = 1
while renameObject in allChildrenName:
renameObject = object + str(i)
i = i+1
return renameObject
else:
for child in parent.children():
if child.objectName() == object:
child.deleteLater()
return object
class TimeScaleBtn(QtWidgets.QPushButton):
def __init__(self, *args , **kwargs):
super(TimeScaleBtn,self).__init__(*args)
self.clicked.connect(self.toggleTimeRange)
self.scaledStartTime = None
self.scaledEndTime = None
self.clickPoint = None
self.pastPoint = None
self.curStartTime = None
self.curEndTime = None
def wheelEvent(self, event):
wheelAngle = event.angleDelta().y()
self.scaledStartTime,self.scaledEndTime = scaleTimeSlider(wheelAngle)
def toggleTimeRange(self):
self.scaledStartTime,self.scaledEndTime = resetTimeSlider(self.scaledStartTime,self.scaledEndTime)
class MainGUI(QtWidgets.QMainWindow):
def __init__(self,*args, **kwargs):
super(MainGUI,self).__init__(*args,**kwargs)
self.setWindowFlags(QtCore.Qt.Tool)
self.mainWidget = QtWidgets.QWidget(self)
mainLayout = QtWidgets.QHBoxLayout(self.mainWidget)
btn = TimeScaleBtn("<->")
btn.setSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Expanding)
mainLayout.addWidget(btn)
self.setCentralWidget(self.mainWidget)
def main():
mayaMainWindow = getTopLevelWidget('MayaWindow')
windowCheck(objectName,mayaMainWindow)
mainGUI = MainGUI(mayaMainWindow)
mainGUI.setObjectName(objectName)
mainGUI.setWindowTitle(objectName)
mainGUI.resize(50,50)
mainGUI.show()
mainGUI.move(50,50)
main()
<-> ボタンの上でマウスホイールをスクロールさせると、タイムスライダーが拡縮します。
ついでに折角ボタンにしたので、ボタンを押すことでframeRangeを最大化したり戻したりできるようにしました。
裏話
ご相談頂いたとき実は、 AIに書かせてみたんだけど動かないんだよねぇ っていう状況でして、
とりあえずそれを元に改修すればいけるかなー とも思ったんですが、
読み解いてみたところ肝心のスクロールをセンシングする部分がファンタジーになってたので
あー・・・うん1から書こうってなりました。
続きはこちら