Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

refreshing script window (or just pulldown list)

Community Beginner ,
Jun 24, 2014 Jun 24, 2014

I have a dropdown list that is populated with the user's selection. If the user changes their selection I would like to provide a way for them to update the dropdown list to reflect that change.

In my script I currently have a button that will close the window and then rebuild it. This causes the dropdown list to be recreated with the updated selection. It's not an elegant solution but works in CS6 however when I try it in CC the entire application freezes. Any thoughts and advice on how to do this in a better way or to fix my code would be appreciated.

Here is the entire script.

var uiPal;

   

//my variables

   

var allLayers = app.project.activeItem.layers;         
var userSelection = app.project.activeItem.selectedLayers;      
var selectionNames = [];
var dimension = 0;
var axisDir = 0;
for (var j=0; j<userSelection.length; j++) selectionNames = userSelection.index + "" + userSelection.name; 
selectionNames.push("Average");
var userCollection = new Array();
var num3d = 0;
var tempPos = [];
for (var i=0; i<userSelection.length; i++)
{
userCollection.push(userSelection.position.value[dimension]);
}

   app.endUndoGroup();

    function buildPal(theObj){

   function buildUI(theObj){
   var myPal = (theObj instanceof Panel) ? theObj : new Window("palette", "KeyFrame Ease", undefined, {resizeable:true});
   if (myPal != null){
   var myResource =  "group{orientation:'column',\
    groupOne: Group{orientation: 'row',\
    myPanelOne: Panel{text:'AXIS', orientation:'row', \
    myRadioButtonX: RadioButton{text: 'X', value: true},\
    myRadioButtonY: RadioButton{text: 'Y', value: false},\
    myRadioButtonZ: RadioButton{text: 'Z', value: false},\
    },\
    myPanelTwo: Panel{text:'AXIS direction:', orientation:'row', \
    myRadioButtonNeg: RadioButton{text: '-', value: false},\
    myRadioButtonAnch: RadioButton{text: '', value: true},\
    myRadioButtonPos: RadioButton{text: '+', value: false},\
    },\
    myPanelThree: Panel{text:'Align To:', orientation:'row', \
    myDropDownList:DropDownList{properties:{items:" + selectionNames.toSource() + "}}\
    },\
    myImage: Image{text:'Image', Image:'`/Desktop/skullIcon.jpg'},\
    },\
    groupTwo: Group{orientation:'row',\
    myButton: Button{text:'Apply', preferredSize: [50,25]},\
    myButton2: Button{text:'Refresh Selection', preferredSize: [120,25]},\
    myButton3: Button{text:'Help', preferredSize: [45,25]},\
    },\
    }";

   myPal.grp = myPal.add(myResource);
          
            myPal.grp.groupOne.myPanelThree.myDropDownList.selection = selectionNames.length -1;

   }
   return myPal;
   }

   uiPal = buildUI(theObj);
  
    // Event listener for the Axis radio buttons. myRadioButtonAllerts user if not all items selected

    uiPal.grp.groupOne.myPanelOne.myRadioButtonX.onClick = uiPal.grp.groupOne.myPanelOne.myRadioButtonY.onClick = uiPal.grp.groupOne.myPanelOne.myRadioButtonZ.onClick = function () {  

   if(uiPal.grp.groupOne.myPanelOne.myRadioButtonX.value) {
   dimension = 0;
   }
   else if(uiPal.grp.groupOne.myPanelOne.myRadioButtonY.value) {
   dimension = 1;
   }
   else if(uiPal.grp.groupOne.myPanelOne.myRadioButtonZ.value) {
   for (var j=0; j<userSelection.length; j++)

          if (userSelection.threeDLayer) num3d++;
          if (num3d != userSelection.length){

            alert ("Not all selected layers are 3D! Please select only 3d layers for use with Z - Axis.");
            uiPal.grp.groupOne.myPanelOne.myRadioButtonX.value = true;
          

            }else{

            dimension = 2;
            return num3d = 0;

     }
   }

    };

    uiPal.grp.groupOne.myPanelTwo.myRadioButtonPos.onClick = uiPal.grp.groupOne.myPanelTwo.myRadioButtonAnch.onClick = uiPal.grp.groupOne.myPanelTwo.myRadioButtonNeg.onClick = function () { 

   if(uiPal.grp.groupOne.myPanelTwo.myRadioButtonPos.value) {
   axisDir = 2;
   }
   else if(uiPal.grp.groupOne.myPanelTwo.myRadioButtonAnch.value) {
   axisDir = 0;
     }
   else if(uiPal.grp.groupOne.myPanelTwo.myRadioButtonNeg.value) {
          axisDir = 1;
     }

    };

//change selection dropdown variable after user selection    li

var ddListSelection = "Average"

uiPal.grp.groupOne.myPanelThree.myDropDownList.onChange = function () {
    ddListSelection = uiPal.grp.groupOne.myPanelThree.myDropDownList.selection
    return ddListSelection
          //alert (userSelection[ddListSelection.index].position.value[dimension]);   
           //num = userSelection[ddListSelection.index].position.value[dimension]
    }

//apply alignment

uiPal.grp.groupTwo.myButton.onClick = function() {

app.beginUndoGroup("bt_3d_Align");

//convert dropdown object to text - contains index of selected layer

var ddIndex = ddListSelection.text

   

if (ddListSelection == "Average" || ddListSelection.text == "Average") {
  
    //create alignToAvg variable and set to average of all numbers
    var alignToAvg = 0
    for (var i=0; i<userCollection.length; i++)
    {
    alignToAvg = alignToAvg + userCollection
    }
    alignToAvg = alignToAvg / userCollection.length
  
    for (i=0;i<userSelection.length;i++) {
    tempPos = userSelection.position.value;
    tempPos[dimension] = alignToAvg;
    if (userSelection.position.isTimeVarying == true) {
    userSelection.position.setValueAtTime(userSelection.time, tempPos);
    }
    else {
    userSelection.position.setValue(tempPos);
    }
    }
    }

   

   

else {
    var fixPos = allLayers[ddIndex.charAt(0)].position.value[dimension];
    for (i=0;i<userSelection.length;i++) {
    //create array to hold position value so that it may be changed
    var tempPos = userSelection.position.value;
  
  
    //place value of selected layer and dimension in to tempPos array
    //if else statments adjusts alignment aka axis direction
    if (userSelection.nullLayer || userSelection.aperture) {
        tempPos[dimension] = fixPos
        }
  
    else {
    if (dimension == 0 && axisDir == 2) {
        tempPos[dimension] = fixPos + ((userSelection.sourceRectAtTime(0,true).width / 2) - (allLayers[ddIndex.charAt(0)].sourceRectAtTime(0,true).width / 2));
    }
    else if (dimension == 0 && axisDir == 1) {
        tempPos[dimension] = fixPos - ((userSelection.sourceRectAtTime(0,true).width / 2) - (allLayers[ddIndex.charAt(0)].sourceRectAtTime(0,true).width / 2));
        }
    else if (dimension == 1 && axisDir == 2) {
        tempPos[dimension] = fixPos + (userSelection.sourceRectAtTime(0,true).height / 2 - (allLayers[ddIndex.charAt(0)].sourceRectAtTime(0,true).height / 2));
        }
    else if (dimension == 1 && axisDir == 1) {
        tempPos[dimension] = fixPos - (userSelection.sourceRectAtTime(0,true).height / 2  - (allLayers[ddIndex.charAt(0)].sourceRectAtTime(0,true).height / 2));
        }
     else { 
         tempPos[dimension] = fixPos
         }
   
     }
   
   
    //if else to determin if layer has keyframes
    if (userSelection.position.isTimeVarying == true) {
      
            userSelection.position.setValueAtTime(userSelection.time, tempPos);
    //userSelection.position.setValueAtTime(userSelection.time, tempPos);
    }
    else { 
    userSelection.position.setValue(tempPos);
   }

  

    //adjust position based on

  

    }
  
    //uiPal.close();
    }

    };

app.endUndoGroup();

uiPal.grp.groupTwo.myButton3.onClick = function() {

   w = new Window ("palette", undefined, undefined,);

myPanel = w.add ("panel");

myStaticText = myPanel.add ("statictext", undefined, undefined, {multiline: true});

myStaticText.size = [800, 400];

myStaticText.text = "How to use this script:\n\n1. Before running script make sure that you have a comp open and selected in the timeline. If you do not the script will warn you and you must run the script again.\n\n2. The script populates its dropdown list when first run. If you wish to change the selection of the layers you will be aligning you must press Refresh Selection.\

\n\n3. AXIS - defines the position value you will be aligning your layer items too. That is, will all layers be aligned to the same x, y, or z position.\

\n\n4. AXIS direction defines the which direction the layer will be aligned  relative to the reference layer selected in the Align To: drop down. This is analagous to Left/Right justification in print or 2D AE layers.\

\n\n5. Align To: picks which layer will be used as the reference point. ie. If you wish all your selection items to have the same x position as 1_greenSolid then you would set 1_greenSolid as your reference layer.\

\n\n6. Apply runs the alignment.\

\n\n7. If you wish to change the layers that you are aligning then you must push Refresh Selection.\

\n\n8. The Average item in the Align To: dropdown takes all the position values of you selected AXIS and averages them out";

w.show ();

}

uiPal.grp.groupTwo.myButton2.onClick = function() {

uiPal.close(); 
allLayers = app.project.activeItem.layers;
userSelection = app.project.activeItem.selectedLayers;
selectionNames = [];
dimension = 0;
axisDir = 0;
for (var j=0; j<userSelection.length; j++) selectionNames = userSelection.index + "" + userSelection.name; 
selectionNames.push("Average");
userCollection = new Array();
num3d = 0;
tempPos = [];
buildPal(theObj);
}

   if (uiPal != null){
   if (uiPal instanceof Window){
   // show the palette
   uiPal.center();
   uiPal.show();
   }else{
   uiPal.layout.layout(true);
   }
   }

    }

   

    buildPal(this);

TOPICS
Scripting
1.2K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Advocate , Jun 28, 2014 Jun 28, 2014

Hi,  i rewrote your script, trying to keep the same variable names but not everywhere.

It does refresh.

You should remove the first entry of your help, a dockable script shouldnt work that way...

Xavier

(function(theObj){

  

    // "globals"

    var uiPal, helpPal, state;

    // current state

    state = {

        dimension : 0,

        axisDir : 0,

        // userSelection: the last user selection (array of layer objects)

        userSelection : [],

        // refIndex : the selection index in t

...
Translate
Advocate ,
Jun 25, 2014 Jun 25, 2014

Hi Brendan,

you don't need to rebuild the whole palette to refresh a dropdown.

Just retrieve the user's selection, update the dropdownmenu and your internal variables (selectionNames, num3d, etc...)

Edit: to update a dropdown with a new array of items (newItems: array of strings), do:

var sel = myDD.selection.text, newSel;

while (myDD.items.length) myDD.remove(myDD.items[0]);

for (var n=0; n<newItems.length; n++){

    newItems === "-" ? myDD.add("separator") : myDD.add("item", newItems);

    if (newItems === sel) newSel =n;

    };

myDD.selection = newSel || 0;

Xavier

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Jun 27, 2014 Jun 27, 2014

Xavier. thanks for the help.

Any way I try to reference the dropdown list I get an error saying the name isn't recognized.

For example  myPal.grp.groupOne.myPanelThree.myDropDownList.selection = selectionNames.length -1; gets an error the myPal is not recognized. I've also tried your code and swapping the myDD.selection with myDropDownList.selection. I get an another error saying myDropDownList isn't recognized even thoughI used that name to build the dropdown. I'm wondering if I'm having this problem because I built the ui with a resource string?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Jun 28, 2014 Jun 28, 2014

The way you declare your UI doesnt influence how it will behave afterwards. So the error is somewhere else, but where, i can't tell.

There are quite a few things that are not so good in your script, like undoGroups, or storing variables that you don't need to store (allLayers, userCollection...).

The only thing that should be stored is userSelection, all other are redundant (dimension etc are stored in the palette widgets).

But even storing the userSelection makes things quite complicated.

It would be much easier if your script worked like the built-in "align" panel: store nothing and reevaluate the user selection everytime the user wants to align something.

Otherwise you are facing possible issues with layers being deleted etc (hence not valid).

I think i would remove that userSelection, and in the dropdown put only 2 items: "average" and "this layer": if 'this layer" is selected, a group (button+static text) appears to alllow identify a layer as reference layer.

Then you only store that specific layer.

Beside all this, aligning layers in 3D is H-A-R-D ...

Xavier.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Jun 28, 2014 Jun 28, 2014

Hi,  i rewrote your script, trying to keep the same variable names but not everywhere.

It does refresh.

You should remove the first entry of your help, a dockable script shouldnt work that way...

Xavier

(function(theObj){

  

    // "globals"

    var uiPal, helpPal, state;

    // current state

    state = {

        dimension : 0,

        axisDir : 0,

        // userSelection: the last user selection (array of layer objects)

        userSelection : [],

        // refIndex : the selection index in the dropdown

        // if refIndex>= userSelection.length : average

        // else the reference layer is userSelection[refIndex]

        refIndex : 0,

        };

  

    // UI : help palette;

    helpPal = new Window ("palette", "KeyFrame Ease : Help", undefined, {resizeable: true});

    helpPal.myPanel = helpPal.add("panel");

    helpPal.myPanel.myStaticText = helpPal.myPanel.add("statictext", undefined, undefined, {multiline: true});

    helpPal.myPanel.myStaticText.preferredSize = [800, 400];

    helpPal.myPanel.myStaticText.text = "How to use this script:\n\n1. Before running script make sure that you have a comp open and selected in the timeline. If you do not the script will warn you and you must run the script again.\n\n2. The script populates its dropdown list when first run. If you wish to change the selection of the layers you will be aligning you must press Refresh Selection.\

\n\n3. AXIS - defines the position value you will be aligning your layer items too. That is, will all layers be aligned to the same x, y, or z position.\

\n\n4. AXIS direction defines the which direction the layer will be aligned  relative to the reference layer selected in the Align To: drop down. This is analagous to Left/Right justification in print or 2D AE layers.\

\n\n5. Align To: picks which layer will be used as the reference point. ie. If you wish all your selection items to have the same x position as 1_greenSolid then you would set 1_greenSolid as your reference layer.\

\n\n6. Apply runs the alignment.\

\n\n7. If you wish to change the layers that you are aligning then you must push Refresh Selection.\

\n\n8. The Average item in the Align To: dropdown takes all the position values of you selected AXIS and averages them out";  

    helpPal.layout.layout(true);

  

  

    // UI : main

    uiPal = (theObj instanceof Panel) ? theObj : new Window("palette", "KeyFrame Ease", undefined, {resizeable:true});

  

    uiPal.grp = uiPal.add("group{orientation:'column',\

                                        groupOne: Group{orientation: 'row',\

                                                        myPanelOne: Panel{text:'AXIS', orientation:'row', \

                                                                                    myRadioButtonX: RadioButton{text: 'X', tag: 0, value: true},\

                                                                                    myRadioButtonY: RadioButton{text: 'Y', tag: 1, value: false},\

                                                                                    myRadioButtonZ: RadioButton{text: 'Z', tag: 2, value: false},\

                                                                                    },\

                                                        myPanelTwo: Panel{text:'AXIS direction:', orientation:'row', \

                                                                                    myRadioButtonNeg: RadioButton{text: '-', tag: 0, value: false},\

                                                                                    myRadioButtonAnch: RadioButton{text: '', tag: 1, value: true},\

                                                                                    myRadioButtonPos: RadioButton{text: '+', tag: 2, value: false},\

                                                                                    },\

                                                        myPanelThree: Panel{text:'Align To:', orientation:'row', \

                                                                                    myDropDownList:DropDownList{properties:{items: ['Average']}}\

                                                                                    },\

                                                        myImage: Image{text:'Image', Image:'`/Desktop/skullIcon.jpg'},\

                                                        },\

                                        groupTwo: Group{orientation:'row',\

                                                                myButton: Button{text:'Apply', preferredSize: [50,25]},\

                                                                myButton2: Button{text:'Refresh Selection', preferredSize: [120,25]},\

                                                                myButton3: Button{text:'Help', preferredSize: [45,25]},\

                                                                },\

                                        }");

    // initially: no userSelection, ==> average

    uiPal.grp.groupOne.myPanelThree.myDropDownList.selection = 0;

  

    uiPal.grp.groupOne.addEventListener("click", onGroupOneClickEvent);

    uiPal.grp.groupOne.myPanelThree.myDropDownList.onChange = onSelectionChange;

    uiPal.grp.groupTwo.myButton.onClick = align;

    uiPal.grp.groupTwo.myButton2.onClick = refresh;

    uiPal.grp.groupTwo.myButton3.onClick = function showHelp(){helpPal.visible ? helpPal.hide() : helpPal.show();};

  

    // update the userSelection straight away:

    refresh();

  

    // show the palette

    helpPal.onResizing = uiPal.onResizing = function(){this.layout.resize();};

    if (uiPal instanceof Window){

      // show the palette

      uiPal.center();

      uiPal.show();

      }

    else{

      uiPal.layout.layout(true);

      };      

  

    //=================

    // SCRIPT FUNCTIONS

    //=================

    // events

    function onGroupOneClickEvent(ev){

        var b = ev.target;

        if (b instanceof RadioButton){

            if (b.parent.text === "AXIS") state.dimension = b.tag

            else state.axisDir = b.tag;

            }

        else if (b instanceof Image){

            // ?

            };

        return;

        };

    function onSelectionChange(){

        var n = this.selection.index;

        state.refIndex = n;

        if (n<this.items.length-1 && !Object.isValid(state.userSelection)) alert("The reference layer is no longer valid. Refresh !");

        return;

        };

    // other functions

    function refresh(){

      

        var

                comp = app.project.activeItem,

                dd = uiPal.grp.groupOne.myPanelThree.myDropDownList,

                oldIndex = dd.selection.index,

                oldText = dd.selection.text,

                doAverage = oldIndex===dd.items.legnth-1,

                n, N;

      

        if (!(comp instanceof CompItem)) return;    // ignore, or display some alert...

      

        state.userSelection = comp.selectedLayers.slice(0).sort(function(a,b){return a.index-b.index;});

        N = state.userSelection.length;

      

        // update the dropdownmenu accordingly

      

        // remove items

        while (dd.children.length) dd.remove(dd.items[0]);

        // add new

        for (n=0; n<N; n++) dd.add("item", state.userSelection.name);

        if (N>0) dd.add("separator");

        dd.add("item", "Average");

        // restore selection  (default = average)

        if (doAverage) dd.selection = dd.items.length-1

        else{

            for (n=0; n<N; n++) if (dd.items.text === oldText) {dd.selection = n; break;};

            if (n===N) dd.selection = dd.items.length-1;

            };

        return;

        };

  

    function checkValidity(){

        // subroutine for "align"

        // see if the script can align layers

        var userSelection = state.userSelection, n, layer;

      

        // no layers

        if (userSelection.length<1) return false;

        // invalid layers

        for (n=0; n<userSelection.length; n++) if (!Object.isValid(userSelection)){

            alert("Some layers are no longer valid, press refresh !");

            return false;

            };

        // non 3D layers

        if (state.dimension === 2){

            for (n=0; n<userSelection.length; n++){

                layer = userSelection;

                if (layer.threeDLayer || layer instanceof CameraLayer || (layer instanceof LightLayer && layer.lightType !== LightType.AMBIENT)){}

                else{

                    alert( layer.lightType === LightType.AMBIENT ? "Can't align ambient lights" : "To align in the Z-direction, all layers should be 3D. Can't continue.");

                    return false;

                    };

                };

            };

        // targetting a comp that is not active:

        if (comp != app.project.activeItem) return confirm("The script layers belong to a comp that is not active. Continue ?");

      

        return true;

        };

    function align(){

      

        // unfold the state object

        var

                dimension = state.dimension,

                axisDir = state.axisDir,      

                userSelection = state.userSelection,

                refIndex = state.refIndex,

                doAverage = refIndex>=userSelection.length,

                refLayer;

      

      

      

        // CHECK VALIDITY: cases of premature exit

        if (!checkValidity()) return;

      

        // THE SCRIPT CAN RUN :

        app.beginUndoGroup("bt_3d_Align");

      

        // align code there

        if (doAverage){

            // more code

            }

        else{

            refLayer = userSelection[refIndex];

            // more code

            }

        app.endUndoGroup();

        return;

        };

    //  

    return;

    })(this);

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jul 07, 2014 Jul 07, 2014
LATEST

Thanks Xavier.Useful learning tool for what to do different the next time around. I appreciate it.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines