Fill layer action fills incorrect layer

Hi, I am creating a clipping group for all selected paint layers. If the layer blending mode is set to hard light I want to fill the Mask Layer with 50% grey. With this code:

doc.setActiveNode(mask_layer)             
    if shading_layer_type == "hard_light":
        view.setForeGroundColor(grey_50)
        app.action('fill_selection_foreground_color').trigger()
        view.setForeGroundColor(fg_color)

It fills the selected layer (the base of the clipping group) instead of the mask layer. If I use a QMessageBox to debug the code before this code it fills the correct layer. I tried with doc.refreshProject() but it doesn’t help.

Any help with be appriciated

I tried with QTest.qWait(1000) but it doesn’t work.

Your issue should be same as this:

Try QTimer.singleShot or watch the undo / undo docker history if you want guarantees

Wrapping the action with the QTimer.singleShot worked. Thanks again @KnowZero!

doc.setActiveNode(shade_layer)  
            
if shading_layer_type == "hard_light":
    view.setForeGroundColor(grey_50)
    QTimer.singleShot(100, lambda: app.action('fill_selection_foreground_color').trigger() )
    view.setForeGroundColor(fg_color)

@KnowZero I was to quick to say that the singleShot was the correct solution. Now I have different problem and that is that it fills with incorrect foreground color.
This is what I tried but it’s not working.

def fill_foreground(color):
    fg_color = view.foregroundColor()
    view.setForeGroundColor(color)
    QTest.qWait(100)
    doc.waitForDone()
    QTimer.singleShot(100, lambda: app.action('fill_selection_foreground_color').trigger())
    view.setForeGroundColor(fg_color)
  
if shading_layer_type == "hard_light":
    QTimer.singleShot(100, lambda: fill_foreground(grey_50))

How do I properly watch the unde/redo docker history to get garantees?

QTimer.singleShot is not a wait command, it yields to the next command, so

view.setForeGroundColor(fg_color)

will likely run before:

app.action(‘fill_selection_foreground_color’).trigger()

You also don’t need to use qWait anymore

As for how to get guarantees from the docker, it would be like this:

from krita import *

def rowchanged(i,i2):
    print ( "Data=",i.data() )
    smodel.currentRowChanged.disconnect(rowchanged)

qdock = next((w for w in Krita.instance().dockers() if w.objectName() == 'History'), None)
wobj = qdock.findChild(QListView)
smodel = wobj.selectionModel()

smodel.currentRowChanged.connect(rowchanged)

The i.data() will contain the action name that you can verify, then disconnect

Thanks again @KnowZero I got it working with your suggestion. I had to use both the history docker and the singlshot like this.

history_docker = next((docker for docker in Krita.instance().dockers() if docker.objectName() == 'History'), None)
history_list_view = history_docker.findChild(QListView)
history_selection_model = history_list_view.selectionModel()

def fill_foreground(color):
    fg_color = view.foregroundColor()
    view.setForeGroundColor(color)
    app.action('fill_selection_foreground_color').trigger()
    view.setForeGroundColor(fg_color)                    
                     
def fill_foreground_deferred(event,_):
    QTimer.singleShot(100, lambda: fill_foreground(grey_50))
    history_selection_model.currentRowChanged.disconnect(fill_foreground_deferred)

if shading_layer_type == "hard_light":
   history_selection_model.currentRowChanged.connect(fill_foreground_deferred)

That looks off to me, it should be more like this:

history_docker = next((docker for docker in Krita.instance().dockers() if docker.objectName() == 'History'), None)
history_list_view = history_docker.findChild(QListView)
history_selection_model = history_list_view.selectionModel()

def fill_foreground(color):
    fg_color = view.foregroundColor()
    view.setForeGroundColor(color)
    app.action('fill_selection_foreground_color').trigger()
                     
                     
def fill_foreground_deferred(event,_):
    history_selection_model.currentRowChanged.disconnect(fill_foreground_deferred)
    view.setForeGroundColor(fg_color)
    

if shading_layer_type == "hard_light":
    history_selection_model.currentRowChanged.connect(fill_foreground_deferred)
    fill_foreground(grey_50)