320 lines
10 KiB
JavaScript
320 lines
10 KiB
JavaScript
#target aftereffects
|
||
|
||
// Ease and Wizz 2.0.4
|
||
// Ian Haigh 2013 (mail@ianhaigh.com)
|
||
|
||
// An After Effects adaptation of Robert Penner's easing equations.
|
||
// Installation and usage at http://aescripts.com/ease-and-wizz/
|
||
// (apologies to Jarvis Cocker)
|
||
|
||
var ease_and_wizz = new Object(); // put all global variables on this object to avoid namespace clashes
|
||
|
||
ease_and_wizz.EASING_FOLDER = 'easingExpressions';
|
||
ease_and_wizz.CLEAR_EXPRESSION_BTN = false; // this adds a button to the palette, "clear", that deletes expressions on all selected properties. Off by default.
|
||
ease_and_wizz.easingEquation = "";
|
||
ease_and_wizz.palette = new Object();
|
||
|
||
// palette controls
|
||
ease_and_wizz.easingList = new Object();
|
||
ease_and_wizz.typeList = new Object();
|
||
ease_and_wizz.keysList = new Object();
|
||
ease_and_wizz.curvaceousCheckbox = new Object();
|
||
|
||
// define values for the controls
|
||
ease_and_wizz.keysLookup = new Object();
|
||
ease_and_wizz.keysLookup['-all'] = 'All';
|
||
ease_and_wizz.keysLookup['-startEnd'] = 'Start and end';
|
||
ease_and_wizz.keysLookup['-startOnly'] = 'Start only';
|
||
|
||
ease_and_wizz.inOutLookup = new Object();
|
||
ease_and_wizz.inOutLookup['inOut'] = 'In + Out';
|
||
ease_and_wizz.inOutLookup['in'] = 'In';
|
||
ease_and_wizz.inOutLookup['out'] = 'Out';
|
||
|
||
ease_and_wizz.easingTypesAry = ['Expo', 'Circ', 'Quint', 'Quart', 'Quad', 'Sine', '-', 'Back', 'Bounce', 'Elastic'];
|
||
|
||
//ease_and_wizz.activeItem;
|
||
//ease_and_wizz.selectedProperties;
|
||
|
||
function ew_getHashValues(hash)
|
||
{ // {{{
|
||
var ary = new Array();
|
||
for (k in hash) {
|
||
ary.push(hash[k]);
|
||
}
|
||
|
||
return ary;
|
||
} // }}}
|
||
|
||
function ew_getHashKeys(hash)
|
||
{ // {{{
|
||
var ary = new Array();
|
||
for (k in hash) {
|
||
ary.push(k);
|
||
}
|
||
|
||
return ary;
|
||
} // }}}
|
||
|
||
function ew_main(thisObj)
|
||
{ //{{{
|
||
ew_createPalette(thisObj);
|
||
} //}}}
|
||
|
||
function ew_getPathToEasingFolder()
|
||
{ // {{{
|
||
// much simpler, thanks Jeff
|
||
var folderObj = new Folder((new File($.fileName)).path + "/" + ease_and_wizz.EASING_FOLDER);
|
||
return folderObj;
|
||
|
||
} // }}}
|
||
|
||
function ew_createPalette(thisObj)
|
||
{//{{{
|
||
var LIST_DIMENSIONS = [0, 0, 120, 15];
|
||
var STATIC_TEXT_DIMENSIONS = [0, 0, 60, 15];
|
||
|
||
ease_and_wizz.palette = (thisObj instanceof Panel) ? thisObj : new Window("palette", "Easing", undefined, {resizeable: true});
|
||
ease_and_wizz.palette.margins = 6;
|
||
ease_and_wizz.palette.alignChildren = 'left';
|
||
|
||
// fix the text display in the popup menu - thanks Jeff Almasol
|
||
var winGfx = ease_and_wizz.palette.graphics;
|
||
var darkColorBrush = winGfx.newPen(winGfx.BrushType.SOLID_COLOR, [0,0,0], 1);
|
||
var lightColorBrush = winGfx.newPen(winGfx.BrushType.SOLID_COLOR, [1,1,1], 1);
|
||
|
||
// popup menus
|
||
// {{{
|
||
|
||
// "easing" menu
|
||
|
||
var easingGrp = ease_and_wizz.palette.add('group', undefined, 'Easing group');
|
||
easingGrp.add('statictext', STATIC_TEXT_DIMENSIONS, 'Easing:');
|
||
|
||
ease_and_wizz.easingList = easingGrp.add('dropdownlist', LIST_DIMENSIONS, ease_and_wizz.easingTypesAry);
|
||
ease_and_wizz.easingList.helpTip = "Choose the type of easing here. They're arranged from most dramatic (expo) to least dramatic (sine), with “special effects” (back, bounce, elastic) at the end.";
|
||
ease_and_wizz.easingList.selection = 'expo';
|
||
ease_and_wizz.easingList.graphics.foregroundColor = darkColorBrush;
|
||
|
||
|
||
// "type" menu
|
||
|
||
var typeGrp = ease_and_wizz.palette.add('group', undefined, 'Type group');
|
||
typeGrp.add('statictext', STATIC_TEXT_DIMENSIONS, 'Type:');
|
||
|
||
ease_and_wizz.typeList = typeGrp.add('dropdownlist', LIST_DIMENSIONS, ew_getHashValues(ease_and_wizz.inOutLookup));
|
||
ease_and_wizz.typeList.selection = 'In + Out';
|
||
ease_and_wizz.typeList.helpTip = "Whether the values ease in, out, or both.";
|
||
ease_and_wizz.typeList.graphics.foregroundColor = darkColorBrush;
|
||
|
||
|
||
// "keys" menu
|
||
|
||
var keysGrp = ease_and_wizz.palette.add('group', undefined, 'Keys group');
|
||
keysGrp.add('statictext', STATIC_TEXT_DIMENSIONS, 'Keys:');
|
||
|
||
ease_and_wizz.keysList = keysGrp.add('dropdownlist', LIST_DIMENSIONS, ew_getHashValues(ease_and_wizz.keysLookup));
|
||
ease_and_wizz.keysList.graphics.foregroundColor = darkColorBrush;
|
||
ease_and_wizz.keysList.helpTip = "When there’s more than two keyframes, this affects whether it eases ALL of the keyframes (the default), the first and last two, or only the first two. Other keyframes will behave as usual.";
|
||
ease_and_wizz.keysList.selection = ew_getHashValues(ease_and_wizz.keysLookup)[0]; // select the first item
|
||
|
||
// }}}
|
||
|
||
// curvaceous checkbox
|
||
var curvaceousGrp = ease_and_wizz.palette.add('group', undefined, 'Curvaceous group');
|
||
ease_and_wizz.curvaceousCheckbox = ease_and_wizz.palette.add('checkbox', undefined, 'Curvaceous');
|
||
ease_and_wizz.curvaceousCheckbox.helpTip = "Turn this on if you’re easing a mask shape or shape path. Note that due to the way it works, Curvaceous automatically disables the “special” easing types, back, bounce, and elastic.";
|
||
|
||
ease_and_wizz.curvaceousCheckbox.value = false;
|
||
|
||
// update the panel
|
||
ease_and_wizz.curvaceousCheckbox.onClick = function() { // {{{
|
||
if (this.value) {
|
||
// it wasn't checked; remove the options that aren't compatible with Curvaceous
|
||
|
||
// before removing options, make sure a valid easing type remains selected
|
||
var curveType = ease_and_wizz.easingList.selection.toString();
|
||
if (curveType == 'Elastic' || curveType == 'Back') ease_and_wizz.easingList.selection = 'Expo';
|
||
|
||
// now take 'em away
|
||
ease_and_wizz.easingList.remove ("Elastic");
|
||
ease_and_wizz.easingList.remove ("Back");
|
||
ease_and_wizz.keysList.remove ("Start only");
|
||
|
||
} else {
|
||
// it was checked, add the missing items
|
||
ease_and_wizz.easingList.add ("item", "Elastic");
|
||
ease_and_wizz.easingList.add ("item", "Back");
|
||
ease_and_wizz.keysList.add ("item", "Start only");
|
||
}
|
||
} // }}}
|
||
|
||
|
||
// apply button
|
||
// {{{
|
||
|
||
var buttonGrp = ease_and_wizz.palette.add('group', undefined, 'Button group');
|
||
buttonGrp.add('statictext', STATIC_TEXT_DIMENSIONS, '');
|
||
|
||
// standard buttons
|
||
if (ease_and_wizz.CLEAR_EXPRESSION_BTN)
|
||
{
|
||
var ew_clearExpressionsBtn = buttonGrp.add('button', undefined, 'Clear expressions');
|
||
ew_clearExpressionsBtn.onClick = ew_clearExpressions;
|
||
}
|
||
|
||
// TODO: add a help button one of these days
|
||
// var easewizz_helpBtn = buttonGrp.add('button', undefined, '?');
|
||
|
||
////////////////////
|
||
// apply button
|
||
////////////////////
|
||
|
||
var applyBtn = buttonGrp.add('button', undefined, 'Apply');
|
||
applyBtn.onClick = ew_applyExpressions;
|
||
|
||
// }}}
|
||
|
||
if (ease_and_wizz.palette instanceof Window)
|
||
{
|
||
ease_and_wizz.palette.show();
|
||
}
|
||
else
|
||
{
|
||
ease_and_wizz.palette.layout.layout(true);
|
||
}
|
||
|
||
}//}}}
|
||
|
||
function ew_trace(s) { // for debugging
|
||
//{{{
|
||
//$.writeln(s); // writes to the ExtendScript interface
|
||
writeLn(s); // writes in the AE info window
|
||
} //}}}
|
||
|
||
function ew_readFile(filename)
|
||
{ //{{{
|
||
var easing_folder = ew_getPathToEasingFolder();
|
||
var file_handle = new File(easing_folder.fsName + '/' + filename);
|
||
|
||
if (!file_handle.exists) {
|
||
throw("I can't find this file: '" + filename + "'. \n\nI looked in here: '" + easing_folder.fsName + "'. \n\nPlease refer to the installation guide and try installing again, or go to:\n\nhttp://aescripts.com/ease-and-wizz/\n\nfor more info.");
|
||
}
|
||
|
||
try {
|
||
file_handle.open('r');
|
||
var the_code = file_handle.read();
|
||
} catch(e) {
|
||
throw("I couldn't read the easing equation file: " + e);
|
||
} finally {
|
||
file_handle.close();
|
||
}
|
||
|
||
return(the_code);
|
||
} //}}}
|
||
|
||
function ew_applyExpressions() { // decide what external file to load
|
||
// {{{
|
||
|
||
|
||
if (!ew_canProceed()) { return false; }
|
||
|
||
app.beginUndoGroup("Ease and Wizz");
|
||
|
||
|
||
// defaults
|
||
var easingType = 'inOut';
|
||
var easeandwizzOrCurvaceous = "-easeandwizz";
|
||
var keyframesToAffect = "-allKeys";
|
||
|
||
// loop through the two menu objects and see what the user's selected
|
||
|
||
// easeAndWizz, or curvaceous?
|
||
if (ease_and_wizz.curvaceousCheckbox.value) easeandwizzOrCurvaceous = "-curvaceous";
|
||
|
||
// which keys should be affected?
|
||
for ( i in ease_and_wizz.keysLookup )
|
||
{
|
||
if (ease_and_wizz.keysLookup[i] == ease_and_wizz.keysList.selection.toString())
|
||
{
|
||
keyframesToAffect = i;
|
||
}
|
||
}
|
||
|
||
// then, should the expression be In, Out, or Both?
|
||
for ( i in ease_and_wizz.inOutLookup )
|
||
{
|
||
if (ease_and_wizz.inOutLookup[i] == ease_and_wizz.typeList.selection.toString()) {
|
||
easingType = i;
|
||
}
|
||
}
|
||
|
||
var curveType = ease_and_wizz.easingList.selection.toString();
|
||
var fileToLoad = "";
|
||
|
||
// very hacky, sorry
|
||
if (curveType == "AE Expo") {
|
||
curveType = "aeExpo";
|
||
fileToLoad = curveType + ".js";
|
||
} else {
|
||
fileToLoad = easingType + curveType + easeandwizzOrCurvaceous + keyframesToAffect + '.js';
|
||
}
|
||
|
||
try {
|
||
ease_and_wizz.easingEquation = ew_readFile(fileToLoad);
|
||
} catch(e) {
|
||
Window.alert(e);
|
||
return false;
|
||
}
|
||
|
||
ew_setProps(ease_and_wizz.easingEquation);
|
||
app.endUndoGroup();
|
||
} // }}}
|
||
|
||
function ew_clearExpressions()
|
||
{//{{{
|
||
// TODO : "Object is invalid"
|
||
// TODO : "null is not an object"
|
||
var selectedProperties = activeItem.selectedProperties;
|
||
for (var f in selectedProperties)
|
||
{
|
||
var currentProperty = selectedProperties[f];
|
||
if (!currentProperty.canSetExpression) { continue; }
|
||
currentProperty.expression = '';
|
||
}
|
||
}//}}}
|
||
|
||
function ew_setProps(expressionCode)
|
||
{ //{{{
|
||
var selectedProperties = app.project.activeItem.selectedProperties;
|
||
|
||
for (var f in selectedProperties)
|
||
{
|
||
var currentProperty = selectedProperties[f];
|
||
|
||
if ((currentProperty.propertyValueType == PropertyValueType.SHAPE) && !ease_and_wizz.curvaceousCheckbox.value) {
|
||
alert("It looks like you have a Mask Path selected. To apply Ease and Wizz to a Mask Path, select the ‘Curvaceous’ checkbox and try again.");
|
||
continue;
|
||
}
|
||
|
||
if (!currentProperty.canSetExpression) { continue; } // don't do anything if we can't set an expression
|
||
if (currentProperty.numKeys < 2) { continue } // likewise if there aren't at least two keyframes
|
||
|
||
currentProperty.expression = expressionCode;
|
||
}
|
||
} //}}}
|
||
|
||
function ew_canProceed()
|
||
{ // {{{
|
||
var activeItem = app.project.activeItem;
|
||
if (activeItem === null)
|
||
{
|
||
Window.alert("Select a keyframe or two.");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
} // }}}
|
||
|
||
ew_main(this);
|
||
|