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

suspendHistory() and ScriptUI palette on BridgeTalk

Advocate ,
Feb 01, 2013 Feb 01, 2013

Hi,

I'm currently working on a project that mixes several needs.

On one hand, I have to pop up a ScriptUI window (non-modal palette), using the BridgeTalk message technique, as outlined here (in order to keep the palette open, waiting for user interaction).

On the other hand, I must build a recordable script (as this tutorial shows).

And finally the History palette has to record one step only - suspendHistory() is needed.

The script:

1. Set some Smart Objects

2. Calls a function that pops up the non-modal Window

3. Then the user interact with GUI elements (sliders, etc) that in turn trigger some extra processing (layers on/off, smart filters, etc).

4. Eventually the user click the Apply/Cancel button, some layer flattening occur, and the Window closes.

I have successfully implemented the above scenario using a Window palette with basically a while-true loop calling waitForRedraw(), but I'm in need to switch to BridgeTalk because, on PCs, the waitForRedraw() seem to keep alive the Window, but doesn't make it truly non-modal (on Mac it works, I've written about it here).

All that said, my problem is, finally, that even though I wrap the Window drawing function into a suspendHistory() statement, being BridgeTalk asynchronous, everything that happens at #3 (user interacting with Window's GUI, triggering layers operations), escapes the suspendHistory step, and makes the History palette dirty - this happens, as far as I understand, because the JS engine doesn't keep itself busy with the Window (as the waitForRedraw() would have done) but goes along instead.

Question: is there any workaround in order to enclose everything in a single history step (or make BridgeTalk synchronous - if it would ever work)?

Thanks in advance!

Davide

TOPICS
Actions and scripting
1.6K
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
Adobe
Advocate ,
Feb 01, 2013 Feb 01, 2013

I've cooked up a very simplified example just to show the dynamic involved:

// EasyWin.jsx

var win, windowResource;

var dup = app.activeDocument.activeLayer.duplicate();

dup.name ="DUP";

var myWin = function() {

          windowResource = "dialog {      orientation: 'column',     alignChildren: ['fill', 'top'],      preferredSize:[300, 130],     text: 'ScriptUI Window - palette',      margins:15,         sliderPanel: Panel {         orientation: 'row',         alignChildren: 'right',         margins:15,         text: ' PANEL ',         st: StaticText { text: 'Value:' },         sl: Slider { minvalue: 1, maxvalue: 100, value: 30, size:[220,20] },            }         bottomGroup: Group{         cd: Checkbox { text:'Checkbox value', value: true },         cancelButton: Button { text: 'Cancel', properties:{name:'cancel'}, size: [120,24], alignment:['right', 'center'] },         applyButton: Button { text: 'Apply', properties:{name:'ok'}, size: [120,24], alignment:['right', 'center'] },     }}";

          win = new Window(windowResource);

          win.sliderPanel.sl.onChanging = function() {

                    this.parent.st.text = Math.floor(this.value);

                    dup.opacity = this.parent.st.text;

          }

          win.bottomGroup.cancelButton.onClick = function() {

                    return win.close();

          };

          win.bottomGroup.applyButton.onClick = function() {

                    return win.close();

          };

          this.run = function() {win.show()}

}

var MyWin = new myWin();

app.activeDocument.suspendHistory('SINGLE STEP','MyWin.run();');

If you run the above code in PS (open at least an image before), a simple Dialog Window will pop up; a copy of the background layer is created and the slider controls the duplicate layer's opacity. Not cool but serves his purpose.

Everything is packed into a single History step - i.e. the history state is written *after* the Apply button click.

Now, try to modify just "dialog" with "palette" and the window will just flashes - it's a known behavior.

// EasyWinCallee.jsx

var win, windowResource;

var dup = app.activeDocument.activeLayer.duplicate();

dup.name ="DUP";

var myWin = function() {

          windowResource = "palette {      orientation: 'column',     alignChildren: ['fill', 'top'],      preferredSize:[300, 130],     text: 'ScriptUI Window - palette',      margins:15,         sliderPanel: Panel {         orientation: 'row',         alignChildren: 'right',         margins:15,         text: ' PANEL ',         st: StaticText { text: 'Value:' },         sl: Slider { minvalue: 1, maxvalue: 100, value: 30, size:[220,20] },            }         bottomGroup: Group{         cd: Checkbox { text:'Checkbox value', value: true },         cancelButton: Button { text: 'Cancel', properties:{name:'cancel'}, size: [120,24], alignment:['right', 'center'] },         applyButton: Button { text: 'Apply', properties:{name:'ok'}, size: [120,24], alignment:['right', 'center'] },     }}";

          win = new Window(windowResource);

          win.sliderPanel.sl.onChanging = function() {

                    this.parent.st.text = Math.floor(this.value);

                    dup.opacity = this.parent.st.text;

          }

          win.bottomGroup.cancelButton.onClick = function() {

                    return win.close();

          };

          win.bottomGroup.applyButton.onClick = function() {

                    return win.close();

          };

          this.run = function() {win.show()}

}

var MyWin = new myWin();

app.activeDocument.suspendHistory('SINGLE STEP','MyWin.run();');

I could use WaitForRedraw() but as I've written before, I can't.

Now, save that file somewhere naming it EasyWinCallee.jsx and, besides it, save another file with this code (saving them is mandatory in order for the following script to read the previous one):

// BTCaller.jsx

#target photoshop

var myPath = File($.fileName).parent;

var callee = new File(myPath + "/EasyWinCallee.jsx");

if (!callee.exists) {alert("Missing!")}

callee.open('r');

var message = callee.read();

callee.close();

var bt = new BridgeTalk();

bt.target = "photoshop";

bt.body = message;

bt.send();

Run BTCaller.

The Palette Window shows and sticks there, but as soon as it's shown, the history status is written and each time you drag the slider a new step is added to the History Palette. Which is what I would like to avoid...

Any suggestion?

Davide

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
Mentor ,
Feb 03, 2013 Feb 03, 2013

This is the best I have come up with so far. It doesn't suspend history but at least it limits all the slider change while the control has focus to one history state.

// EasyWinCallee.jsx

var win, windowResource;

var controlHistory = false;

var doc = app.activeDocument;

var dup = doc.activeLayer.duplicate();

app.activeDocument.activeLayer = dup;

dup.invert();

dup.name ="DUP";

var myWin = function() {

          windowResource = "palette {      orientation: 'column',     alignChildren: ['fill', 'top'],      preferredSize:[300, 130],     text: 'ScriptUI Window - palette',      margins:15,         sliderPanel: Panel {         orientation: 'row',         alignChildren: 'right',         margins:15,         text: ' PANEL ',         st: StaticText { text: 'Value:' },         sl: Slider { minvalue: 1, maxvalue: 100, value: 30, size:[220,20] },            }         bottomGroup: Group{         cd: Checkbox { text:'Checkbox value', value: true },         cancelButton: Button { text: 'Cancel', properties:{name:'cancel'}, size: [120,24], alignment:['right', 'center'] },         applyButton: Button { text: 'Apply', properties:{name:'ok'}, size: [120,24], alignment:['right', 'center'] },     }}";

          win = new Window(windowResource);

          win.sliderPanel.sl.onChange = function() {

                    this.parent.st.text = Math.floor(this.value);

                    if(controlHistory){

                        doc.activeHistoryState = doc.historyStates[doc.historyStates.length-2];

                    }else{

                        controlHistory = true;

                    }

                    dup.opacity = this.parent.st.text;

          }

      win.sliderPanel.sl.addEventListener('blur', BlurHandler);

          win.bottomGroup.cancelButton.onClick = function() {

                    return win.close();

          };

          win.bottomGroup.applyButton.onClick = function() {

                    return win.close();

          };

          this.run = function() {win.show()}

}

function BlurHandler(){

    controlHistory = false;

}

var MyWin = new myWin();

app.activeDocument.suspendHistory('SINGLE STEP','MyWin.run();');

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 ,
Feb 04, 2013 Feb 04, 2013
LATEST

Thanks Mike, I appreciate you've taken some time to help!

I'm not sure I could implement this one (into a recordable script - shouldn't everything go into a single, "standard" history status?) but it looks very like the only compromise. I'll let you know if I come up with something different.

Thanks again!

Davide

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