Bug 475819 - Node.setVisible() doesn't refresh like manually clicking the eyeball icon on each layer does
Summary: Node.setVisible() doesn't refresh like manually clicking the eyeball icon on ...
Status: REPORTED
Alias: None
Product: krita
Classification: Applications
Component: Scripting (other bugs)
Version First Reported In: 5.2.0
Platform: Manjaro Linux
: NOR normal
Target Milestone: ---
Assignee: Krita Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-10-19 02:44 UTC by varkatope
Modified: 2023-10-19 02:44 UTC (History)
0 users

See Also:
Latest Commit:
Version Fixed/Implemented In:
Sentry Crash Report:


Attachments
A .kra file with 3 groups of layers. Run the above script on it in Scripter. (340.32 KB, application/x-krita)
2023-10-19 02:44 UTC, varkatope
Details

Note You need to log in before you can comment on or make changes to this bug.
Description varkatope 2023-10-19 02:44:36 UTC
Created attachment 162416 [details]
A .kra file with 3 groups of layers. Run the above script on it in Scripter.

SUMMARY
My plugin has a function where it loops through the layer stack and sets setCollapsed(True) and setVisible(False) on everything, and then uses several buttons to focus a particular group with setCollapsed(False) and setVisible(True). This works pretty well in and of itself, but I've run into an issue where using setVisible() in Python doesn't redraw the canvas when switching layer groups, which means it hangs onto old data. Now, you may be saying "use Document.refreshProjection()," which is what I was doing before. However, this works OK on a 1024x1024 document, is fairly annoying at 2K, and is brain meltingly slow at 4K and above (as in, from "several" to "dozens" of minutes to rebuild depending on resolution and content), so I've stopped using it unless absolutely necessary. Here's what actually does work to force a quick redraw: manually toggling the eye icon on the group off and on, and strangely, adding a deactivated clone layer with no source specified to the bottom of the group. The second of these is what I'm currently doing as I can add the clone layer programmatically and it does redraw the canvas fast enough to be useful, but it's an ugly, ugly hack and adding extra layers eats into the video ram usage. If Node.setVisible() worked like manually clicking on the eye icon, I could potentially switch the group off and on again to redraw the canvas at a reasonable speed.

STEPS TO REPRODUCE
1. Open attached .kra file and run below script multiple times.
2. It should toggle through the groups.
3. Going from group G1 to G2 likely won't redraw the canvas properly, and then going from group G2 to G3 will redraw successfully every time because I added a deactivated clone layer there to illustrate the point.
4. Going from G3 back to G1 (group with a clone layer back to a group without one) may or may not work every time.
5. Clicking manually on the eye icon of groups G1 and G2 will also redraw the canvas, but just running the script a few times on the same groups will not do so.

Test code:

from krita import Krita

doc = Krita.instance().activeDocument()
root = doc.rootNode()
children = root.childNodes()

def collapseAndDeactivate():
    for child in children:
        child.setVisible(False)
        child.setCollapsed(True)
    
def toggleNode():
    collapseAndDeactivate()
    newActive = doc.activeNode()
    
    if newActive.name() == "G1":
        newActive = doc.nodeByName("G2")
    elif newActive.name() == "G2":
        newActive = doc.nodeByName("G3")
    elif newActive.name() == "G3":
        newActive = doc.nodeByName("G1")
    else:
        newActive = doc.nodeByName("G1")
    
    newActive.setVisible(True)
    newActive.setCollapsed(False)
    doc.setActiveNode(newActive)
    
collapseAndDeactivate()
toggleNode()



OBSERVED RESULT
There's clearly some extra magic going on in the clone layer and visibility button code that I'm not able to access through Python (I tried looking at the C++ source and also got deep into Qt but I'm not seeing anything super relevant, or it seems relevant but doesn't actually work). I don't want to refresh the entire document's projection, I just need whatever's currently visible.

EXPECTED RESULT
Either Node.setVisible() forces the same canvas refresh that manually clicking the eye icon does or there's a dedicated function that redraws just whatever is currently visible without doing a full Document.refreshProjection(), which isn't really usable past 1-2K.