0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MayaAdvent Calendar 2024

Day 18

timeSliderをスケールしたい

Last updated at Posted at 2024-12-17

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()

<-> ボタンの上でマウスホイールをスクロールさせると、タイムスライダーが拡縮します。
image.png

ついでに折角ボタンにしたので、ボタンを押すことでframeRangeを最大化したり戻したりできるようにしました。

裏話

ご相談頂いたとき実は、 AIに書かせてみたんだけど動かないんだよねぇ っていう状況でして、
とりあえずそれを元に改修すればいけるかなー とも思ったんですが、
読み解いてみたところ肝心のスクロールをセンシングする部分がファンタジーになってたので
あー・・・うん1から書こうってなりました。

続きはこちら

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?