【脚本案例】rd_Scooter 图层时间与关键帧控制

介绍

把图层/关键帧/标记玩透了,拆完即无敌

// 此脚本显示带有滑动和滑动控件的面板
// 图层设置,例如图层素材源、输入/输出范围、标记和关键帧。
// 对图层编辑操作进行更强大控制的设置。

界面

【脚本案例】rd_Scooter 图层时间与关键帧控制

其他

免费购买:https://aescripts.com/rd-scooter/

作者:

源码

// rd_Scooter.jsx
// AES:https://aescripts.com/rd-scooter/
// Copyright (c) 2005-2013 redefinery (Jeffrey R. Almasol). All rights reserved.
// check it: www.redefinery.com
// 
// Name: rd_Scooter
// Version: 3.1
// 
// 描述:
// 此脚本显示带有滑动和滑动控件的面板
// 图层设置,例如图层素材源、输入/输出范围、标记和关键帧。
// 对图层编辑操作进行更强大控制的设置。
//
// 注意: Keyframes 设置为 Selected 选项,脚本可能会需要一段时间才能完成,具体取决于关键帧的数量和选定的设置。
// 此外,此选项仅适用于第一个选定图层。
//
// 您可以使用四个导航按钮。帧偏移
// 出现在每个按钮上方,但您可以将它们更改为任何正值数字。这些偏移量被保存为设置以供后续使用会话。
//
// 注意:此版本的脚本需要 After Effects CS5或以后。它可以用作可停靠面板,
// 通过放置Scripts 文件夹的 ScriptUI Panels 子文件夹中的脚本,
// 然后从窗口菜单中选择这个脚本。
//
// 最初由 Stu Maschwitz 请求。谢谢你的挑战。
//
// 法律申明:
// 此脚本按“原样”提供,不提供任何形式的保证,明示或暗示。在任何情况下,作者均不对任何损害承担责任因使用此脚本而以任何方式产生。
//
// 换句话说,我只是想与我分享知识并帮助我
// AE 脚本负责人,所以如果我的代码没有评级,请不要怪我。 :-)

// rd_Scooter()
// 
// Description:
// This function contains the main logic for this script.
// 
// Parameters:
// thisObj - "this" object.
// 
// Returns:
// Nothing.
//
(function rd_Scooter(thisObj)
{
    // Globals

    var rd_ScooterData = new Object();  // Store globals in an object
    rd_ScooterData.scriptName = "rd: Scooter";
    rd_ScooterData.scriptTitle = rd_ScooterData.scriptName + " v3.1";

    rd_ScooterData.strAffectPnl = {en: "Affect"};
    rd_ScooterData.strLayerSrc = {en: "Layer Source"};
    rd_ScooterData.strLayerInOut = {en: "Layer In/Out"};
    rd_ScooterData.strLayerMarkers = {en: "Layer Markers"};
    rd_ScooterData.strKfs = {en: "Keyframes:"};
    rd_ScooterData.strKfsNone = {en: "None"};
    rd_ScooterData.strKfsSel = {en: "Selected"};
    rd_ScooterData.strKfsAll = {en: "All"};
    rd_ScooterData.strRew = {en: "<<"};
    rd_ScooterData.strPrev = {en: "<"};
    rd_ScooterData.strNext = {en: ">"};
    rd_ScooterData.strFwd = {en: ">>"};
    rd_ScooterData.strHelp = {en: "?"};
    rd_ScooterData.strErrNoWorkToDo = {en: "No operation to perform because no options are selected."};
    rd_ScooterData.strErrNoCompSel = {en: "Cannot perform operation. Please select or open a single composition in the Project panel, and try again."};
    rd_ScooterData.strErrNoLayerSel = {en: "Cannot perform operation. Please select at least one layer, and try again."};
    rd_ScooterData.strMinAE100 = {en: "This script requires Adobe After Effects CS5 or later."};
    rd_ScooterData.strHelpText = 
    {
        en: "Copyright (c) 2005-2013 redefinery (Jeffrey R. Almasol). \n" +
        "All rights reserved.\n" +
        "\n" +
        "This script displays a palette with controls for slipping and sliding various layer settings, such as layer footage source, in/out range, markers, and keyframes. You can use different combinations of these settings for more powerful control over layer editing operations.\n" +
        "\n" +
        "Note: If you select the Keyframes = Selected option, the script might take awhile to finish, depending on the number of keyframes and the selected settings. Also, this option works on only the first selected layer.\n" +
        "\n" +
        "There are four navigation buttons that you can use. The frame offset appears above each button, but you can change these to any positive number. These offsets are saved as settings for use in subsequent sessions.\n" +
        "\n" +
        "Note: This version of the script requires After Effects CS5 or later. It can be used as a dockable panel by placing the script in a ScriptUI Panels subfolder of the Scripts folder, and then choosing this script from the Window menu.\n" +
        "\n" +
        "Originally requested by Stu Maschwitz. Thanks for the challenge.\n"
    };

    // rd_Scooter_localize()
    // 
    // Description:
    // This function localizes the given string variable based on the current locale.
    // 
    // Parameters:
    //   strVar - The string variable's name.
    // 
    // Returns:
    // String.
    //
    function rd_Scooter_localize(strVar)
    {
        return strVar["en"];
    }

    // rd_Scooter_buildUI()
    // 
    // Description:
    // This function builds the user interface.
    // 
    // Parameters:
    // thisObj - Panel object (if script is launched from Window menu); null otherwise.
    // 
    // Returns:
    // Window or Panel object representing the built user interface.
    //
    function rd_Scooter_buildUI(thisObj)
    {
        var pal = (thisObj instanceof Panel) ? thisObj : new Window("palette", rd_ScooterData.scriptName, undefined, {resizeable:true});

        if (pal !== null)
        {
            var res = 
            "group { \
                orientation:'column', alignment:['fill','top'], \
                header: Group { \
                    alignment:['fill','top'], \
                    title: StaticText { text:'" + rd_ScooterData.scriptName + "', alignment:['fill','center'] }, \
                    help: Button { text:'" + rd_Scooter_localize(rd_ScooterData.strHelp) +"', maximumSize:[30,20], alignment:['right','center'] }, \
                }, \
                affectPnl: Panel { \
                    orientation:'row', text:'" + rd_Scooter_localize(rd_ScooterData.strAffectPnl) + "', alignment:['fill','top'], \
                    c1: Group { \
                        orientation:'column', alignment:['left','top'], alignChildren:['fill','top'], \
                        layerSrc: Checkbox { text:'" + rd_Scooter_localize(rd_ScooterData.strLayerSrc) + "', value:true }, \
                        layerInOut: Checkbox { text:'" + rd_Scooter_localize(rd_ScooterData.strLayerInOut) + "', value:true }, \
                        layerMarkers: Checkbox { text:'" + rd_Scooter_localize(rd_ScooterData.strLayerMarkers) + "', value:true }, \
                    }, \
                    c2: Group { \
                        orientation:'column', alignment:['right','top'], alignChildren:['right','top'], \
                        kfs: StaticText { text:'" + rd_Scooter_localize(rd_ScooterData.strKfs) + "', alignment:['right','top'] }, \
                    }, \
                    c3: Group { \
                        orientation:'column', alignChildren:['left','top'], \
                        kfsNone: RadioButton { text:'" + rd_Scooter_localize(rd_ScooterData.strKfsNone) + "' }, \
                        kfsSel: RadioButton { text:'" + rd_Scooter_localize(rd_ScooterData.strKfsSel) + "' }, \
                        kfsAll: RadioButton { text:'" + rd_Scooter_localize(rd_ScooterData.strKfsAll) + "', value:true }, \
                    }, \
                }, \
                flds: Group { \
                    alignment:['fill','top'], \
                    rewVal: EditText { text:'10', alignment:['fill','top'], justify:'center', preferredSize:[-1,20] }, \
                    prevVal: EditText { text:'1', alignment:['fill','top'], justify:'center', preferredSize:[-1,20] }, \
                    nextVal: EditText { text:'1', alignment:['fill','top'], justify:'center', preferredSize:[-1,20] }, \
                    fwdVal: EditText { text:'10', alignment:['fill','top'], justify:'center', preferredSize:[-1,20] }, \
                }, \
                btns: Group { \
                    alignment:['fill','top'], \
                    rew: Button { text:'" + rd_Scooter_localize(rd_ScooterData.strRew) + "', alignment:['fill','top'], preferredSize:[30,20] }, \
                    prev: Button { text:'" + rd_Scooter_localize(rd_ScooterData.strPrev) + "', alignment:['fill','top'], preferredSize:[30,20] }, \
                    next: Button { text:'" + rd_Scooter_localize(rd_ScooterData.strNext) + "', alignment:['fill','top'], preferredSize:[30,20] }, \
                    fwd: Button { text:'" + rd_Scooter_localize(rd_ScooterData.strFwd) + "', alignment:['fill','top'], preferredSize:[30,20] }, \
                }, \
            }";
            pal.grp = pal.add(res);
//                      shiftBtn: Button { text:'" + rd_Scooter_localize(rd_ScooterData.strShift) + "' }, \
            pal.grp.affectPnl.c2.margins.left += 10;

            pal.layout.layout(true);
            pal.grp.minimumSize = pal.grp.size;
            pal.layout.resize();
            pal.onResizing = pal.onResize = function () {this.layout.resize();}

            pal.grp.btns.rew.preferredSize.width = pal.grp.flds.rewVal.preferredSize.width;
            pal.grp.btns.prev.preferredSize.width = pal.grp.flds.prevVal.preferredSize.width;
            pal.grp.btns.next.preferredSize.width = pal.grp.flds.nextVal.preferredSize.width;
            pal.grp.btns.fwd.preferredSize.width = pal.grp.flds.fwdVal.preferredSize.width;

            pal.grp.flds.rewVal.onChange = rd_Scooter_doValidatePosNum;
            pal.grp.flds.prevVal.onChange = rd_Scooter_doValidatePosNum;
            pal.grp.flds.nextVal.onChange = rd_Scooter_doValidatePosNum;
            pal.grp.flds.fwdVal.onChange = rd_Scooter_doValidatePosNum;

            pal.grp.header.help.onClick = function () {alert(rd_ScooterData.scriptTitle + "\n" + rd_Scooter_localize(rd_ScooterData.strHelpText), rd_ScooterData.scriptName);}
            pal.grp.btns.rew.onClick = function() {rd_Scooter_doScoot(-this.parent.parent.flds.rewVal.text, this.parent.parent);}
            pal.grp.btns.prev.onClick = function() {rd_Scooter_doScoot(-this.parent.parent.flds.prevVal.text, this.parent.parent);}
            pal.grp.btns.next.onClick = function() {rd_Scooter_doScoot(this.parent.parent.flds.nextVal.text, this.parent.parent);}
            pal.grp.btns.fwd.onClick = function() {rd_Scooter_doScoot(this.parent.parent.flds.fwdVal.text, this.parent.parent);}
        }

        return pal;
    }

    // rd_Scooter_doValidatePosNum()
    // 
    // Description:
    // This callback function assures that the entered value is a
    // positive number.
    // 
    // Parameters:
    // None.
    // 
    // Returns:
    // Nothing.
    //
    function rd_Scooter_doValidatePosNum()
    {
        var enteredValue = this.text;

        // If not a number or less than 0, reset to 1
        if (isNaN(enteredValue) || (enteredValue <= 0))
            this.text = "1";
    }

    // rd_Scooter_scootLayerMarkers()
    // 
    // Description:
    // This function shifts the specified layer's markers by the specified distance (in seconds).
    // 
    // Parameters:
    //   layer - Layer object containing markers.
    //   offset - Time in seconds to offset the layer's markers.
    // 
    // Returns:
    // None.
    //
    function rd_Scooter_scootLayerMarkers(layer, offset)
    {
        var markerProps = layer.property("Marker");
        var marker;

        // Loop through the layer's markers in the direction such that new
        // markers will not affect the indices of existing markers
        if (offset > 0)
        {
            for (var i=markerProps.numKeys; i>=1; i--)
            {
                markerProps.setValueAtTime(markerProps.keyTime(i)+offset, markerProps.keyValue(i));
                markerProps.removeKey(i);
            }
        }
        else
        {
            var newTime, newValue;

            for (var i=1; i<=markerProps.numKeys; i++)
            {
                newTime = markerProps.keyTime(i) + offset;
                newValue = markerProps.keyValue(i)
                markerProps.setValueAtTime(newTime, newValue);
                markerProps.removeKey(i+1);
            }
        }
    }

    function rd_Scooter_shiftKeyToNewTime(prop, keyToCopy, offset, keyToRemove)
    {
//      var newTime = prop.keyTime(keyToCopy) + offset;
        //var newValue = prop.keyValue(keyToCopy);
//      var newKeyIndex, inInterp, outInterp;

        // Create the new keyframe
        //prop.setValueAtTime(newTime, newValue);

//      $.writeln("    in interp : "+getPropInterpType(prop.keyInInterpolationType(k)));
//      $.writeln("    out interp: "+getPropInterpType(prop.keyOutInterpolationType(k)));
//      if (prop.propertyValueType === PropertyValueType.TwoD_SPATIAL)
//      {
//          spatialTangent = prop.keyInSpatialTangent(k);
//          $.writeln("    in spatial tangent : "+spatialTangent[0]+", "+spatialTangent[1]);
//          spatialTangent = prop.keyOutSpatialTangent(k);
//          $.writeln("    out spatial tangent: "+spatialTangent[0]+", "+spatialTangent[1]);
//          $.writeln("    roving: "+prop.keyRoving(k));
//          $.writeln("    spatial auto bezier: "+prop.keySpatialAutoBezier(k));
//          $.writeln("    spatial continuous : "+prop.keySpatialContinuous(k));
//      }
//      else if (prop.propertyValueType === PropertyValueType.ThreeD_SPATIAL)
//      {
//          spatialTangent = prop.keyInSpatialTangent(k);
//          $.writeln("    in spatial tangent : "+spatialTangent[0]+", "+spatialTangent[1]+", "+spatialTangent[2]);
//          spatialTangent = prop.keyOutSpatialTangent(k);
//          $.writeln("    out spatial tangent: "+spatialTangent[0]+", "+spatialTangent[1]+", "+spatialTangent[2]);
//          $.writeln("    roving: "+prop.keyRoving(k));
//          $.writeln("    spatial auto bezier: "+prop.keySpatialAutoBezier(k));
//          $.writeln("    spatial continuous : "+prop.keySpatialContinuous(k));
//      }
//      eases = prop.keyInTemporalEase(k);
//      for (e=0; e<eases.length; e++)
//          $.writeln("    in temporal  ease# "+(e+1)+": speed="+eases[e].speed+" infl="+eases[e].influence);
//      eases = prop.keyOutTemporalEase(k);
//      for (e=0; e<eases.length; e++)
//          $.writeln("    out temporal ease# "+(e+1)+": speed="+eases[e].speed+" infl="+eases[e].influence);
//      $.writeln("    temporal auto bezier: "+prop.keyTemporalAutoBezier(k));
//      $.writeln("    temporal continuous : "+prop.keyTemporalContinuous(k));

        // Remember the key's settings before creating the new setting, just in case creating the new key affects keyToCopy's settings
        var inInterp = prop.keyInInterpolationType(keyToCopy);
        var outInterp = prop.keyOutInterpolationType(keyToCopy);
        var keyToCopyValue = prop.keyValue(keyToCopy);

//      $.writeln("shifting key#"+keyToCopy+" of prop '"+prop.name+"'");

        if ((inInterp === KeyframeInterpolationType.BEZIER) && (outInterp === KeyframeInterpolationType.BEZIER))
        {
            var tempAutoBezier = prop.keyTemporalAutoBezier(keyToCopy);
            var tempContBezier = prop.keyTemporalContinuous(keyToCopy);
        }
        if (outInterp !== KeyframeInterpolationType.HOLD)
        {
            var inTempEase = prop.keyInTemporalEase(keyToCopy);
            var outTempEase = prop.keyOutTemporalEase(keyToCopy);
        }
        if ((prop.propertyValueType === PropertyValueType.TwoD_SPATIAL) || (prop.propertyValueType === PropertyValueType.ThreeD_SPATIAL))
        {
            var spatAutoBezier = prop.keySpatialAutoBezier(keyToCopy);
            var spatContBezier = prop.keySpatialContinuous(keyToCopy);
            var inSpatTangent = prop.keyInSpatialTangent(keyToCopy);
            var outSpatTangent = prop.keyOutSpatialTangent(keyToCopy);
            var roving = prop.keyRoving(keyToCopy);
        }

        // Create the new keyframe
        var newTime = prop.keyTime(keyToCopy) + offset;
//      $.writeln("adding new key...");
        var newKeyIndex = prop.addKey(newTime);
//      $.writeln("setting new key's value...");
        prop.setValueAtKey(newKeyIndex, keyToCopyValue);

        if (outInterp !== KeyframeInterpolationType.HOLD)
        {
//          $.writeln("setting temp ease...");
            prop.setTemporalEaseAtKey(newKeyIndex, inTempEase, outTempEase);
        }

        // Copy over the keyframe settings
//      $.writeln("setting interp...");
        prop.setInterpolationTypeAtKey(newKeyIndex, inInterp, outInterp);

        if ((inInterp === KeyframeInterpolationType.BEZIER) && (outInterp === KeyframeInterpolationType.BEZIER) && tempContBezier)
        {
//          $.writeln("setting temp cont...");
            prop.setTemporalContinuousAtKey(newKeyIndex, tempContBezier);
//          $.writeln("setting temp auto bez...");
            prop.setTemporalAutoBezierAtKey(newKeyIndex, tempAutoBezier);       // Implies Continuous, so do after it
        }

        if ((prop.propertyValueType === PropertyValueType.TwoD_SPATIAL) || (prop.propertyValueType === PropertyValueType.ThreeD_SPATIAL))
        {
//          $.writeln("setting spat cont...");
            prop.setSpatialContinuousAtKey(newKeyIndex, spatContBezier);
//          $.writeln("setting spat auto bez...");
            prop.setSpatialAutoBezierAtKey(newKeyIndex, spatAutoBezier);        // Implies Continuous, so do after it

//          $.writeln("setting spat tangents...");
            prop.setSpatialTangentsAtKey(newKeyIndex, inSpatTangent, outSpatTangent);

//          $.writeln("setting roving...");
            prop.setRovingAtKey(newKeyIndex, roving);
        }

        // Remove the old keyframe
//      $.writeln("removing key...");
        prop.removeKey(keyToRemove);
    }

    // rd_Scooter_scootAllPropGroupKeys()
    // 
    // Description:
    // This function shifts the specified layer's keyframes (all except markers) by the specified distance (in seconds).
    // 
    // Parameters:
    //   propGroup - PropertyGroup object (initially, the Layer object) containing keyframes.
    //   offset - Time in seconds to offset the layer's keyframes.
    // 
    // Returns:
    // None.
    //
    function rd_Scooter_scootAllPropGroupKeys(propGroup, offset)
    {
        var prop, newTime, newValue, keyIndex;

        // Iterate over the specified property group's properties
        for (var i=1; i<=propGroup.numProperties; i++)
        {
            var keyTimes = new Array();

            prop = propGroup.property(i);
            if (prop.propertyType === PropertyType.PROPERTY)            // Found a property
            {
                if (prop.matchName === "ADBE Marker")             // Skip markers; they're processed separately
                    continue;
                if (!prop.isTimeVarying)                            // Skip properties that aren't keyframed
                    continue;

                // Loop through the property's keyframes in the direction such that new
                // keyframes will not affect the indices of existing keyframes
                if (offset > 0)
                {
                    for (var j=prop.numKeys; j>=1; j--)
                        rd_Scooter_shiftKeyToNewTime(prop, j, offset, j);
                }
                else
                {
                    for (var j=1; j<=prop.numKeys; j++)
                        rd_Scooter_shiftKeyToNewTime(prop, j, offset, j+1);
                }
            }
            else if (prop.propertyType === PropertyType.INDEXED_GROUP)  // Found an indexed group, so check its nested properties
                rd_Scooter_scootAllPropGroupKeys(prop, offset);
            else if (prop.propertyType === PropertyType.NAMED_GROUP)    // Found a named group, so check its nested properties
                rd_Scooter_scootAllPropGroupKeys(prop, offset);
        }
    }

    // rd_Scooter_getSelectedPropGroupKeys()
    // 
    // Description:
    // This function retrieves the selected or unselected properties and keyframes (no markers) of the specified property group.
    // 
    // Parameters:
    //   propGroup - PropertyGroup object (initially, the Layer object) containing keyframes.
    //   whichKeys - Value controlling which keys to retrieve (0 = unselected, 1 = selected)
    // 
    // Returns:
    // Array of PropInfo objects representing properties and their selected or unselected key times.
    //
    function rd_Scooter_getSelectedPropGroupKeys(propGroup, whichKeys)
    {
        var props = new Array();
        var prop, propInfo;

        // Iterate over the specified property group's properties
        for (var i=1; i<=propGroup.numProperties; i++)
        {
            prop = propGroup.property(i);
            if (prop.propertyType === PropertyType.PROPERTY)            // Found a property
            {
                if (prop.matchName === "ADBE Marker")             // Skip markers; they're processed separately
                    continue;
                if (!prop.isTimeVarying)                            // Skip properties that aren't keyframed
                    continue;

                propInfo = new Object;
                propInfo.prop = prop;
                propInfo.keyTimes = new Array();

                for (var j=1; j<=prop.numKeys; j++)
                    if (((whichKeys === 0) && !prop.keySelected(j)) || ((whichKeys === 1) && prop.keySelected(j)))
                        propInfo.keyTimes[propInfo.keyTimes.length] = prop.keyTime(j);

                // If there were keys to save, add the property and its keys to the props array
                if (propInfo.keyTimes.length > 0)
                    props[props.length] = propInfo;
            }
            else if (prop.propertyType === PropertyType.INDEXED_GROUP)  // Found an indexed group, so check its nested properties
                props = props.concat(rd_Scooter_getSelectedPropGroupKeys(prop, whichKeys));
            else if (prop.propertyType === PropertyType.NAMED_GROUP)    // Found a named group, so check its nested properties
                props = props.concat(rd_Scooter_getSelectedPropGroupKeys(prop, whichKeys));
        }

        return props;
    }

    // rd_Scooter_scootSelectedPropGroupKeys()
    // 
    // Description:
    // This function shifts the specified layer's keyframes (selected or unselected, except markers) 
    // by the specified distance (in seconds).
    // 
    // Parameters:
    //   propGroup - PropertyGroup object (initially, the Layer object) containing keyframes.
    //   offset - Time in seconds to offset the layer's keyframes.
    //   whichKeys - Value controlling which keys to offset (0 = unselected, 1 = selected)
    // 
    // Returns:
    // None.
    //
    function rd_Scooter_scootSelectedPropGroupKeys(propGroup, offset, whichKeys)
    {
        var props = rd_Scooter_getSelectedPropGroupKeys(propGroup, whichKeys);
        var prop, propKeyTimes, keyIndex;

        for (var i=0; i<props.length; i++)
        {
            prop = props[i].prop;
            propKeyTimes = props[i].keyTimes;

            // Loop through the property's keyframes in the direction such that new
            // keyframes will not affect the indices of existing keyframes
            if (offset > 0)
            {
                for (var j=propKeyTimes.length-1; j>=0; j--)
                {
                    keyIndex = prop.nearestKeyIndex(propKeyTimes[j]);
                    rd_Scooter_shiftKeyToNewTime(prop, keyIndex, offset, keyIndex);
                }
            }
            else
            {
                for (var j=0; j<propKeyTimes.length; j++)
                {
                    keyIndex = prop.nearestKeyIndex(propKeyTimes[j]);
                    rd_Scooter_shiftKeyToNewTime(prop, keyIndex, offset, keyIndex+1);
                }
            }
        }
    }

    // rd_Scooter_doScoot()
    // 
    // Description:
    // This function performs the actual "scooting" operation.
    // 
    // Parameters:
    //   scootDist - Amount of offset, in seconds.
    //   pal - The palette (Window object) itself.
    // 
    // Returns:
    // Nothing.
    //
    function rd_Scooter_doScoot(scootDist, pal)
    {
        // Check if any work (scooting, options) to be done
        if (scootDist === 0)
            return;

        var layerSrc = pal.affectPnl.c1.layerSrc.value;
        var layerInOut = pal.affectPnl.c1.layerInOut.value;
        var layerMarkers = pal.affectPnl.c1.layerMarkers.value;
        var kfsNone = pal.affectPnl.c3.kfsNone.value, kfsSelected = pal.affectPnl.c3.kfsSel.value, kfsAll = pal.affectPnl.c3.kfsAll.value;

        if (!layerSrc && !layerInOut && !layerMarkers && kfsNone)
        {
            alert(rd_Scooter_localize(rd_ScooterData.strErrNoWorkToDo), rd_ScooterData.scriptName);
            return;
        }

        // Check that a project exists
        if (app.project === null)
            return;

        // Get the current (active/frontmost) comp
        var comp = app.project.activeItem;

        if ((comp === null) || !(comp instanceof CompItem))
        {
            alert(rd_Scooter_localize(rd_ScooterData.strErrNoCompSel), rd_ScooterData.scriptName);
            return;
        }

        // If no layers are selected, nothing to do
        if (comp.selectedLayers.length === 0)
        {
            alert(rd_Scooter_localize(rd_ScooterData.strErrNoLayerSel), rd_ScooterData.scriptName);
            return;
        }

        // Process each selected layer
        app.beginUndoGroup(rd_ScooterData.scriptName);

        var layers = comp.selectedLayers, layer;
        var offset = scootDist * comp.frameDuration, startTime, stretch;

        for (var i=0; i<layers.length; i++)
        {
            layer = layers[i];
            stretch = layer.stretch / 100;

            if (layerSrc)                       // Moving layer source?
            {
                layer.startTime += offset;
                if (!layerInOut)
                {
                    layer.inPoint -= offset;

                    // Calculate the outPoint, compensating for the stretch value and startTime. Ugh!
                    startTime = layer.inPoint - ((layer.inPoint - layer.startTime) / stretch);
                    layer.outPoint = layer.outPoint - startTime * stretch;
                }

                // If not moving all keyframes, adjust keyframes accordingly
                // Note: Keyframes need to be moved before markers; otherwise, the selected keys get unselected
                if (kfsSelected)
                    rd_Scooter_scootSelectedPropGroupKeys(layer, -offset, 0);
                else if (kfsNone)
                    rd_Scooter_scootAllPropGroupKeys(layer, -offset);

                // If moving layer source, but not markers, adjust markers accordingly
                if (!layerMarkers)
                    rd_Scooter_scootLayerMarkers(layer, -offset)
            }
            else if (layerInOut)                // Moving layer in/out?
            {
                layer.inPoint += offset;

                // Calculate the outPoint, compensating for the stretch value and startTime. Ugh!
                startTime = layer.inPoint - ((layer.inPoint - layer.startTime) / stretch);
                layer.outPoint = layer.outPoint - startTime * stretch;
            }

            // If moving all or some keyframes, adjust accordingly
            // Note: Keyframes need to be moved before markers; otherwise, the selected keys get unselected
            if (!layerSrc)
            {
                if (kfsSelected)
                    rd_Scooter_scootSelectedPropGroupKeys(layer, offset, 1);
                else if (kfsAll)
                    rd_Scooter_scootAllPropGroupKeys(layer, offset);
            }

            if (layerMarkers)                   // Moving layer markers?
            {
                // If moving markers, but not layer source, adjust markers accordingly
                if (!layerSrc)
                    rd_Scooter_scootLayerMarkers(layer, offset)
            }
        }

        app.endUndoGroup();
    }

    // main code:
    //

    // Prerequisites check
    if (parseFloat(app.version) < 10.0)
        alert(rd_Scooter_localize(rd_ScooterData.strMinAE100), rd_ScooterData.scriptName);
    else
    {
        // Build and show the console's floating palette
        var rdscPal = rd_Scooter_buildUI(thisObj);
        if (rdscPal !== null)
        {
            // Update UI values, if saved in the settings
            if (app.settings.haveSetting("redefinery", "rd_Scooter_layerSrc"))
                rdscPal.grp.affectPnl.c1.layerSrc.value = (app.settings.getSetting("redefinery", "rd_Scooter_layerSrc") === "false") ? false : true;
            if (app.settings.haveSetting("redefinery", "rd_Scooter_layerInOut"))
                rdscPal.grp.affectPnl.c1.layerInOut.value = (app.settings.getSetting("redefinery", "rd_Scooter_layerInOut") === "false") ? false : true;
            if (app.settings.haveSetting("redefinery", "rd_Scooter_layerMarkers"))
                rdscPal.grp.affectPnl.c1.layerMarkers.value = (app.settings.getSetting("redefinery", "rd_Scooter_layerMarkers") === "false") ? false : true;

            if (app.settings.haveSetting("redefinery", "rd_Scooter_kfsNone"))
                rdscPal.grp.affectPnl.c3.kfsNone.value = (app.settings.getSetting("redefinery", "rd_Scooter_kfsNone") === "false") ? false : true;
            if (app.settings.haveSetting("redefinery", "rd_Scooter_kfsSel"))
                rdscPal.grp.affectPnl.c3.kfsSel.value = (app.settings.getSetting("redefinery", "rd_Scooter_kfsSel") === "false") ? false : true;
            if (app.settings.haveSetting("redefinery", "rd_Scooter_kfsAll"))
                rdscPal.grp.affectPnl.c3.kfsAll.value = (app.settings.getSetting("redefinery", "rd_Scooter_kfsAll") === "false") ? false : true;

            if (app.settings.haveSetting("redefinery", "rd_Scooter_rewValue"))
                rdscPal.grp.flds.rewVal.text = app.settings.getSetting("redefinery", "rd_Scooter_rewValue").toString();
            if (app.settings.haveSetting("redefinery", "rd_Scooter_prevValue"))
                rdscPal.grp.flds.prevVal.text = app.settings.getSetting("redefinery", "rd_Scooter_prevValue").toString();
            if (app.settings.haveSetting("redefinery", "rd_Scooter_nextValue"))
                rdscPal.grp.flds.nextVal.text = app.settings.getSetting("redefinery", "rd_Scooter_nextValue").toString();
            if (app.settings.haveSetting("redefinery", "rd_Scooter_fwdValue"))
                rdscPal.grp.flds.fwdVal.text = app.settings.getSetting("redefinery", "rd_Scooter_fwdValue").toString();

            // Save current UI settings upon closing the palette
            rdscPal.onClose = function()
            {
                app.settings.saveSetting("redefinery", "rd_Scooter_layerSrc", rdscPal.grp.affectPnl.c1.layerSrc.value);
                app.settings.saveSetting("redefinery", "rd_Scooter_layerInOut", rdscPal.grp.affectPnl.c1.layerInOut.value);
                app.settings.saveSetting("redefinery", "rd_Scooter_layerMarkers", rdscPal.grp.affectPnl.c1.layerMarkers.value);

                app.settings.saveSetting("redefinery", "rd_Scooter_kfsNone", rdscPal.grp.affectPnl.c3.kfsNone.value);
                app.settings.saveSetting("redefinery", "rd_Scooter_kfsSel", rdscPal.grp.affectPnl.c3.kfsSel.value);
                app.settings.saveSetting("redefinery", "rd_Scooter_kfsAll", rdscPal.grp.affectPnl.c3.kfsAll.value);

                app.settings.saveSetting("redefinery", "rd_Scooter_rewValue", rdscPal.grp.flds.rewVal.text);
                app.settings.saveSetting("redefinery", "rd_Scooter_prevValue", rdscPal.grp.flds.prevVal.text);
                app.settings.saveSetting("redefinery", "rd_Scooter_nextValue", rdscPal.grp.flds.nextVal.text);
                app.settings.saveSetting("redefinery", "rd_Scooter_fwdValue", rdscPal.grp.flds.fwdVal.text);
            }

            if (rdscPal instanceof Window)
            {
                // Show the palette
                rdscPal.center();
                rdscPal.show();
            }
            else
                rdscPal.layout.layout(true);
        }
    }
})(this);

给TA充电
共{{data.count}}人
人已充电
AE开发脚本开发

【脚本案例】将变换的关键帧修复到邻近整数关键帧

2021-9-30 4:03:18

AE开发脚本开发

【脚本案例】合成批量加时间码

2021-9-30 11:09:50

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
搜索