setActiveNode does not change active node

The script I’m trying to make puts an outline behind the current layer and places both the outline layer and original layer in a group. I’ve gotten most of it working how I want, the issue I’ve run into is that after the script finishes, the active layer is the (clone of) the original layer I was working on, and I want it to be the group that the original layer and outline layer have been placed into.

Using the setActiveNode command seems to do nothing.

I’ve attempted a fix proposed in other similar threads using this sleep function:

but it seems to have no effect; I’ve tried up to 5000. I’ve also sprinkled in waitForDone all over the place to no avail either. I’m new to scripting so it’s a bit noodley, but this is what I have:

from krita import *
from PyQt5.QtGui import (QColor,)

inst = Krita.instance()
doc = inst.activeDocument()
toOutline = doc.activeNode()

inst.action('selectopaque').trigger()
inst.action('growselection').trigger()
doc.waitForDone()

i = InfoObject()
i.setProperty("color", QColor(255, 255, 255))

outline = doc.createFillLayer("Outline", "color", i, doc.selection())
group = doc.createGroupLayer("01")
toOutline.parentNode().addChildNode(group, toOutline)

nodes = [outline, toOutline.clone()]

for node in nodes:
   group.addChildNode(node, None)

toOutline.remove()
inst.action('deselect').trigger()
doc.waitForDone()
doc.setActiveNode(group)

You can just add the group last. Any new layer added would get focus so moving toOutline.parentNode().addChildNode(group, toOutline) down after the addChildNode loop would achieve what you want without the setActiveNode. In general, it is best to build all your layer structures first, then add the whole structure at once rather than adding them one by one

1 Like

If you realy like to edit current node and selected nodes following script can be used. Have fun.

from krita import Krita

from PyQt5.QtCore import Qt, QModelIndex, QItemSelectionModel
from PyQt5.QtWidgets import QTreeView


def get_layer_model():
    app = Krita.instance()
    kis_layer_box = next((d for d in app.dockers() if d.objectName() == 'KisLayerBox'), None)
    view = kis_layer_box.findChild(QTreeView, 'listLayers')
    return view.model(), view.selectionModel()


def node_to_index(node, model):
    path = list()
    while node and (node.index() >= 0):
        path.insert(0, node.index())
        node = node.parentNode()

    index = QModelIndex()    
    for i in path:
        last_row = model.rowCount(index) - 1
        index = model.index(last_row - i, 0, index)
    return index


def index_to_node(index, document):
    if not index.isValid():
        raise RuntimeError('Invalid index')
    model = index.model()
    path = list()
    while index.isValid():
        last_row = model.rowCount(index.parent()) - 1
        path.insert(0, last_row - index.row())
        index = index.parent()
        
    node = None
    children = document.topLevelNodes()
    for i in path:
        node = children[i]
        children = node.childNodes()
    return node

# testing:
# following script will change target_node to be current node,
# also selection is kept and extended to current node.
#
# before running: 
# create new document, and add some nodes and node groups
# add one node named target_node

app = Krita.instance()
doc = app.activeDocument()

target_node = doc.nodeByName('target_node')
model, s_model = get_layer_model()
index = node_to_index(target_node, model)

s_model.setCurrentIndex(index, QItemSelectionModel.Select)  # or QItemSelectionModel.SelectCurrent

/AkiR

2 Likes

That works with some finagling, thank you! I’m still wrapping my head around the idea of manipulating layers that aren’t added to the layer hierarchy yet