timeSliderをスケールしたい

timeSliderをスケールしたいんだわ
と相談がありまして。

詳しく聞くと
- マウスのスクロールでスケールしたい
- 現在のフレームを中心にスケールしたい

という感じでした。

もう少し詳しく考えると
- どんなに広げても、start/endFrameがmax
- どんなに小さくしても今のフレーム+前後１fずつがmin

ですかね。

タイムレンジのスケール自体はまぁきっと問題ないとして、
スクロールをどこで検知させるかですね。

適当なQtWidgetsつくってその上でイベント拾ってしまうのが簡単かなぁ
※ほんとはタイムスライダー上でスクロールのイベント拾えれば良いのですが、ちょっと探しても出てこないので。


実装
--

```python
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/82065ee2-a70e-a66a-aecf-ab9796bebb76.png)

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

裏話
--

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



続きはこちら

https://qiita.com/9boz/items/52adc437320fbcf7e33c