Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (function selectSpecifiedKeyframes() {
- // Ensure an active composition and at least one selected layer.
- var comp = app.project.activeItem;
- if (!(comp && comp instanceof CompItem)) {
- alert("Please select a composition.");
- return;
- }
- var layers = comp.selectedLayers;
- if (layers.length === 0) {
- alert("Please select at least one layer.");
- return;
- }
- // Helper function: recursively gather properties that have keyframes.
- function gatherKeyframedProperties(propGroup, propSet) {
- for (var i = 1; i <= propGroup.numProperties; i++) {
- var prop = propGroup.property(i);
- if (prop.canSetExpression && prop.numKeys && prop.numKeys > 0) {
- propSet[prop.name] = true;
- }
- if (prop.propertyType === PropertyType.NAMED_GROUP || prop.propertyType === PropertyType.INDEXED_GROUP) {
- gatherKeyframedProperties(prop, propSet);
- }
- }
- }
- // Build a list of property names (from selected layers) that have keyframes.
- var keyframedProps = {};
- for (var l = 0; l < layers.length; l++) {
- gatherKeyframedProperties(layers[l], keyframedProps);
- }
- var propNames = [];
- for (var name in keyframedProps) {
- propNames.push(name);
- }
- if (propNames.length === 0) {
- alert("No keyframed properties found in the selected layers.");
- return;
- }
- // Create the dialog for property and keyframe option selection.
- var dlg = new Window("dialog", "Select Property and Keyframe");
- dlg.orientation = "column";
- dlg.alignChildren = "left";
- dlg.add("statictext", undefined, "Select a property:");
- var propDropdown = dlg.add("dropdownlist", undefined, propNames);
- propDropdown.selection = 0;
- dlg.add("statictext", undefined, "Select keyframe option:");
- var keyframeDropdown = dlg.add("dropdownlist", undefined, ["First", "Last", "Middle", "Range"]);
- keyframeDropdown.selection = 0;
- // Range input group – only visible when "Range" is selected.
- var rangeGroup = dlg.add("group", undefined, "Range Inputs");
- rangeGroup.orientation = "row";
- rangeGroup.alignChildren = "center";
- rangeGroup.add("statictext", undefined, "From:");
- var rangeFrom = rangeGroup.add("edittext", undefined, "1");
- rangeFrom.characters = 3;
- rangeGroup.add("statictext", undefined, "To:");
- var rangeTo = rangeGroup.add("edittext", undefined, "1");
- rangeTo.characters = 3;
- rangeGroup.visible = false;
- keyframeDropdown.onChange = function() {
- rangeGroup.visible = (keyframeDropdown.selection.text === "Range");
- };
- var continueBtn = dlg.add("button", undefined, "Continue", {name:"ok"});
- continueBtn.onClick = function() {
- dlg.close();
- };
- dlg.show();
- // Get user selections.
- var selectedPropertyName = propDropdown.selection.text;
- var keyframeOption = keyframeDropdown.selection.text;
- var rangeStart, rangeEnd;
- if (keyframeOption === "Range") {
- rangeStart = parseInt(rangeFrom.text, 10);
- rangeEnd = parseInt(rangeTo.text, 10);
- if (isNaN(rangeStart) || isNaN(rangeEnd) || rangeStart < 1 || rangeEnd < rangeStart) {
- showMessage("Invalid range input!");
- return;
- }
- }
- // Helper function: check if a keyframe is a hold keyframe.
- function isHoldKeyframe(prop, index) {
- try {
- return (prop.keyInInterpolationType(index) === KeyframeInterpolationType.HOLD ||
- prop.keyOutInterpolationType(index) === KeyframeInterpolationType.HOLD);
- } catch (e) {
- return false;
- }
- }
- app.beginUndoGroup("Select Specified Keyframes");
- var anyValid = false;
- var someMissing = false;
- // Process each selected layer.
- for (var i = 0; i < layers.length; i++) {
- var foundProp = findPropertyByName(layers[i], selectedPropertyName);
- if (foundProp) {
- var numKeys = foundProp.numKeys;
- // Deselect all keyframes.
- for (var k = 1; k <= numKeys; k++) {
- foundProp.setSelectedAtKey(k, false);
- }
- var indicesToSelect = [];
- if (keyframeOption === "First") {
- if (numKeys >= 1) { indicesToSelect.push(1); }
- else { someMissing = true; }
- } else if (keyframeOption === "Last") {
- if (numKeys >= 1) { indicesToSelect.push(numKeys); }
- else { someMissing = true; }
- } else if (keyframeOption === "Middle") {
- if (numKeys > 2) {
- for (var j = 2; j < numKeys; j++) { indicesToSelect.push(j); }
- } else { someMissing = true; }
- } else if (keyframeOption === "Range") {
- if (numKeys >= rangeEnd) {
- for (var r = rangeStart; r <= rangeEnd; r++) { indicesToSelect.push(r); }
- } else { someMissing = true; }
- }
- if (indicesToSelect.length > 0) {
- // For each index to select, if it's a hold keyframe, temporarily convert it to linear.
- var holdData = {}; // Store original interpolation data.
- for (var idx = 0; idx < indicesToSelect.length; idx++) {
- var kIndex = indicesToSelect[idx];
- if (isHoldKeyframe(foundProp, kIndex)) {
- var origIn = foundProp.keyInInterpolationType(kIndex);
- var origOut = foundProp.keyOutInterpolationType(kIndex);
- holdData[kIndex] = { origIn: origIn, origOut: origOut };
- foundProp.setInterpolationTypeAtKey(kIndex, KeyframeInterpolationType.LINEAR, KeyframeInterpolationType.LINEAR);
- }
- foundProp.setSelectedAtKey(kIndex, true);
- }
- // Now revert any hold keyframes back to their original interpolation.
- for (var idx in holdData) {
- var indexNum = parseInt(idx, 10);
- var data = holdData[idx];
- foundProp.setInterpolationTypeAtKey(indexNum, data.origIn, data.origOut);
- }
- anyValid = true;
- }
- } else {
- someMissing = true;
- }
- }
- app.endUndoGroup();
- var totalSelected = 0;
- for (var i = 0; i < layers.length; i++) {
- var prop = findPropertyByName(layers[i], selectedPropertyName);
- if (prop) {
- totalSelected += prop.selectedKeys.length;
- }
- }
- if (totalSelected === 0) {
- throw new Error("No keyframes ended up being selected even though keyframes exist.");
- }
- // Provide feedback.
- if (!anyValid) {
- showMessage("No Keyframes Found!");
- } else if (someMissing) {
- showMessage("Some layers are missing keyframes!");
- } else {
- showMessage("Task Complete!");
- }
- // Recursive function to find a property by name (case-insensitive).
- function findPropertyByName(propGroup, nameToFind) {
- for (var j = 1; j <= propGroup.numProperties; j++) {
- var prop = propGroup.property(j);
- if (prop.name.toLowerCase() === nameToFind.toLowerCase()) {
- return prop;
- }
- if (prop.propertyType === PropertyType.NAMED_GROUP || prop.propertyType === PropertyType.INDEXED_GROUP) {
- var found = findPropertyByName(prop, nameToFind);
- if (found) { return found; }
- }
- }
- return null;
- }
- // Function to display a dialog with a "Continue" button.
- function showMessage(msg) {
- var win = new Window("dialog", "Notification");
- win.orientation = "column";
- win.alignChildren = "center";
- win.add("statictext", undefined, msg);
- var btn = win.add("button", undefined, "Continue");
- btn.onClick = function() { win.close(); };
- win.show();
- }
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement