Skip to main content
Tonee Gee
Participating Frequently
January 14, 2018
Question

ScriptUI Photoshop Slider - lag vs. latency

  • January 14, 2018
  • 2 replies
  • 1307 views

Hello all,

I have the following script, running on Mac, with ESTK.

As you can see, it's just a simple slider, in a Dialog window, that talks to Photoshop and change a layer opacity value.

I have made the passed value from the Dialog Window as fast as possible (I think), i.e. the value of the slider changed by the user gets almost instantly, no lag (minimal that is) to Photoshop.

However, and this is where my question rests : if the user starts to click on the Slider repeatedly, one can notice that the slider gets "unavailable" for a short period of time. I think this might have something to do with WaitForRedraw ? Is there anyway that we could bypass this "latency", by somehow making ScriptUI slider as instant as possible ?

Thank you !

#target Photoshop

function SnpCreateSlider ()

{

this.windowRef = null;

}

cTID = function (s) {

    return app.charIDToTypeID(s);

    };

sTID = function (s) {

    return app.stringIDToTypeID(s);

    };

SnpCreateSlider.prototype.run = function() {

var retval = true;

// Create a palette-type window (a modeless or floating dialog),

    var win = new Window("dialog", "SnpCreateSlider", [150, 150, 600, 300]);

    this.windowRef = win;

    var CurrentV = 100;

// Add a panel to contain the components

win.pnl = win.add("panel", [10, 10, 440, 100], "Move slider around");

// Add some labels that describe the state of the slider

win.pnl.minLbl = win.pnl.add("statictext", [20, 47, 35, 60], "0");

win.pnl.curLbl = win.pnl.add("statictext", [115, 47, 170, 60], "50");

win.pnl.maxLbl = win.pnl.add("statictext", [210, 47, 250, 60], "100");

win.pnl.displayTextLbl = win.pnl.add("statictext", [290, 20, 380, 40], "Current value:");

win.pnl.displayLbl = win.pnl.add("edittext", [385, 20, 425, 40], CurrentV);

// Add a slider control

win.pnl.sliderCtrl = win.pnl.add("slider", [20, 20, 230, 45], CurrentV, 0, 100);

    // SHORTCUTS

    var myVal = win.pnl.displayLbl;

    var mySlider = win.pnl.sliderCtrl;

// Add buttons

    win.refreshButton = win.add("button", [125, 110, 125, 140], "Refresh");

win.resetButton = win.add("button", [25, 110, 125, 140], "Reset");

win.doneButton = win.add("button",[320, 110, 420, 140] , "Done");

   

   

   

    var sliderChangeCallback = function (event) {

        var myValue = myVal.text = Math.round(mySlider.value);

        win.pnl.enabled = false; // DISABLE GUI

        myRoutine (myValue);

        win.pnl.enabled = true; // ENABLE GUI

        }

    

    var sliderChangingCallback = function (event) {

        myVal.text = Math.round(mySlider.value);

        }

    

// EVENT LISTENERS

    mySlider.addEventListener ('change', sliderChangeCallback, false);

    mySlider.addEventListener ('changing', sliderChangingCallback,false);

   

    mySlider.addEventListener ('mouseup', waitForRedraw);

   

   

// MY ROUTINE

    var myRoutine = function (vv) {

        myVal.text = vv;

        // TALKS TO PHOTOSHOP

        app.activeDocument.activeLayer.opacity = vv;

    }

function waitForRedraw () { 

    var d; 

    d = new ActionDescriptor(); 

    d.putEnumerated(stringIDToTypeID('state'), stringIDToTypeID('state'), stringIDToTypeID('redrawComplete')); 

    executeAction(stringIDToTypeID('wait'), d, DialogModes.NO); 

    }  

function _waitForRedraw () { 

    var desc = new ActionDescriptor();

    desc.putEnumerated(cTID("Stte"), cTID("Stte"), cTID("RdCm"));

    executeAction(cTID("Wait"), desc, DialogModes.NO);

    }

function __waitForRedraw () { 

    var eventWait = charIDToTypeID("Wait");

    var enumRedrawComplete = charIDToTypeID("RdCm") ;

    var typeState = charIDToTypeID("Stte");

    var keyState = charIDToTypeID("Stte");

    var desc = new ActionDescriptor();

    desc.putEnumerated(keyState, typeState, enumRedrawComplete);

    executeAction(eventWait, desc, DialogModes.NO);

    }

    win.refreshButton.onClick = waitForRedraw;

    win.onMove = waitForRedraw;

   

// Define behavior for the "Exit" button

win.doneButton.onClick = function ()

{

win.close();

};

// Define behavior for the "Reset" button

win.resetButton.onClick = function()

{

win.pnl.sliderCtrl.value = 100;

win.pnl.curLbl.text = 100;

win.pnl.displayLbl.text= 100;

}

// Display the window

    win.center();

win.show();

return retval;

}

if(typeof(SnpCreateSlider_unitTest) == "undefined") {

    new SnpCreateSlider().run();

}

P.S :

To show the latency "issue" here, replace :

mySlider.addEventListener ('mouseup', showLatency);

function showLatency () {

win.pnl.enabled = false; // DISABLE GUI

waitForRedraw () ;  

win.pnl.enabled = true; // ENABLE GUI

    }

This topic has been closed for replies.

2 replies

Jarda Bereza
Inspiring
January 15, 2018

In website javascript, you could do something like:

1) click on button

2) delay action by 150ms via setTimeout()

3) if you click on button again and you are faster than 150ms then reset your timeout to new 150ms via clearTimeout()

4) if you didn't do anything in 150ms then delayed action is fired

Anyway JSX doesn't have these very basic functions. So you can't do that.

Geppetto Luis
Legend
January 15, 2018

Your script on my mac is too slow

you place a script below that I find faster

see if it's right for you

//https://forums.adobe.com/message/3660601#3660601

//Michael L Hale

var d= new Window('dialog'); 

          d.grpOpacity = d.add('group'); 

          d.grpOpacity.orientation = 'column'; 

          d.grpOpacity.alignChildren = ['fill','top']; 

          d.grpOpacity.grpSlider = d.grpOpacity.add('group'); 

          d.grpOpacity.grpSlider.spacing = 0; 

          d.grpOpacity.grpSlider.orientation = 'column'; 

          d.grpOpacity.grpSlider.st1 =  d.grpOpacity.grpSlider.add('statictext',undefined,'Opacity'); 

          d.grpOpacity.grpSlider.st1.alignment = 'left'; 

          d.grpOpacity.grpSlider.grpSlider = d.grpOpacity.grpSlider.add('group'); 

          d.grpOpacity.grpSlider.grpSlider.alignChildren = ['left','center']; 

          d.grpOpacity.grpSlider.grpSlider.spacing = 0; 

          d.slOpacity = d.grpOpacity.grpSlider.grpSlider.add('slider',undefined,0,0,100); 

          d.slOpacity.value = app.activeDocument.activeLayer.opacity; 

          d.slOpacity.preferredSize.width = 200; 

          d.etOpacityValue = d.grpOpacity.grpSlider.grpSlider.add('edittext'); 

          d.etOpacityValue.text = Math.round(app.activeDocument.activeLayer.opacity); 

          d.etOpacityValue.addEventListener ('keydown', InitEditKeyboardHandler ); 

          d.etOpacityValue.preferredSize.width = 40; 

          d.grpOpacity.grpSlider.grpSlider.stUnit = d.grpOpacity.grpSlider.grpSlider.add('statictext',undefined,'%'); 

 

          d.grpOpacity.grpSlider.grpSt = d.grpOpacity.grpSlider.add('group'); 

          d.grpOpacity.grpSlider.grpSt.orientation = 'row'; 

          d.grpOpacity.grpSlider.grpSt.alignment = 'fill'; 

          d.grpOpacity.grpSlider.grpSt.spacing = 0; 

          d.grpOpacity.grpSlider.grpSt.margins = [5,0,0,0]; 

          d.grpOpacity.grpSlider.grpSt.grpLeft = d.grpOpacity.grpSlider.grpSt.add('group'); 

          d.grpOpacity.grpSlider.grpSt.grpLeft.st1 = d.grpOpacity.grpSlider.grpSt.grpLeft.add('statictext',undefined,'0'); 

          d.grpOpacity.grpSlider.grpSt.grpLeft.st1.alignment = ['left','center']; 

          d.grpOpacity.grpSlider.grpSt.grpLeft.st1.preferredSize.width = 150; 

          d.grpOpacity.grpSlider.grpSt.grpLeft.st3 = d.grpOpacity.grpSlider.grpSt.grpLeft.add('statictext',undefined,'100'); 

          d.grpOpacity.grpSlider.grpSt.grpLeft.st3.alignment = ['right','center']; 

          d.grpOpacity.grpSlider.grpSt.grpLeft.st3.preferredSize.width = 40; 

           

          d.grpButtons = d.add('group'); 

          d.grpButtons.alignment = "right"; 

          d.grpButtons.btnCanel = d.grpButtons.add( 'button', undefined, 'Cancel', { name:'cancel' }); 

          d.grpButtons.btnOK = d.grpButtons.add( 'button', undefined, 'Ok', { name:'ok' }); 

           

          d.etOpacityValue.onChanging = d.etOpacityValue.onChange = function(){ 

                                                                                                              var d = FindDialog(this); 

                                                                                                              d.slOpacity.value = Number(this.text); 

                                                                                                              d.slOpacity.onChange(); 

                                                                                                               

                                                                                                              } 

          d.slOpacity.onChanging  = d.slOpacity.onChange = function(){ 

                                                                                var d = FindDialog(this); 

                                                                                d.etOpacityValue.text = Math.round(this.value); 

                                                                           } 

       d.slOpacity.onChange = function(){ 

                                                                                var d = FindDialog(this); 

                                                                                app.activeDocument.activeLayer.opacity = Math.round(this.value); 

                                                                                app.refresh(); 

                                                                           } 

           

d.show(); 

 

function FindDialog( inItem ) { 

     var w = inItem; 

     while ( 'dialog' != w.type ) { 

          if ( undefined == w.parent ) { 

               w = null; 

               break; 

          } 

          w = w.parent; 

     } 

     return w; 

}; 

function InitEditKeyboardHandler (event) { 

    try { 

        var keyIsOK = KeyIsNumeric(event) || 

                                   KeyIsDelete(event) ||  

                                   KeyIsLRArrow(event) || 

                                   KeyIsTabEnterEscape(event);                  

        if (! keyIsOK) { 

            event.preventDefault(); 

            app.beep(); 

        } 

    } 

    catch (e) { 

    } 

}; 

//    key identifier functions 

function KeyIsNumeric ( event ) { 

    return   ( event.keyName.match( /[0-9]/) != null ) && ! KeyHasModifier ( event ); 

function KeyIsPeriod ( event ) { 

    return  ( event.keyName.match( /Period/) != null ) && ! KeyHasModifier ( event ); 

function KeyIsComma ( event ) { 

    return  ( event.keyName.match( /Comma/) != null ) && ! KeyHasModifier ( event ); 

function KeyHasModifier ( event ) { 

    return event.shiftKey || event.ctrlKey || event.altKey || event.metaKey; 

function KeyIsDelete (event) { 

    //    Shift-delete is ok 

    return (event.keyName == 'Backspace') && ! (event.ctrlKey); 

function KeyIsLRArrow (event) { 

    return ((event.keyName == 'Left') || (event.keyName == 'Right')) && ! (event.altKey || event.metaKey); 

function KeyIsTabEnterEscape (event) { 

     return event.keyName == 'Tab' || event.keyName == 'Enter' || event.keyName == 'Escape'; 

Jarda Bereza
Inspiring
January 15, 2018

Why do you need wait for redraw?

It usually takes 700 - 1500ms

Tonee Gee
Tonee GeeAuthor
Participating Frequently
January 15, 2018

Hi Jarda Bereza,

if we don't use app.refresh OR WaitForRedraw function, Photoshop don't refresh - obviously  - so we don't get any visual update on the Opacity changes...or...am I missing something ? Or is there another way to update PS faster ?

Thanks