Draft: Better Timeline to Storyboard Synchronization
I started this initial design in attempt to solve BUG:441150, but it will take more time since there are multiple factors that need to be considered with regards to how the timeline and the storyboard interact with one another and may take some reconsidering of how the storyboard data is managed and reflected in other parts of the GUI. Since there are other tasks we need to take care of for Krita 5.0's immediate release, I am punting this for now and taking notes on what needs to be done in a public place so that users can be assured that this will be addressed at a later date and so that I can pick up this MR again once the dust settles on Krita 5's launch.
Initially, my plan was to try to improve timeline-to-storyboard synchronization so that it was on par with the reverse implementation. While I still believe that the proper workflow for an animated sequence should be Storyboard First, Then Animate Frame-By-Frame
, it is true that the current design does not allow for storyboards to be easily modified within the timeline view. When I began trying to find a quick-fix for this issue, my plan was to:
- Track keyframe changes within the storyboard docker when it's interested (has storyboards to manage, has more than 1, etc.)
- Based on what type of keyframe changes occurred (Have all frames left the scope of a scene? Have all starting frames of a scene been moved deeper within a scenes' duration?), we try to infer whether the user intended to "merge" scenes together (Remove a scene and extend the previous scene's duration by the duration of the removed scene) or whether the starting time of the scene needs to be increased and the duration of the previous scene needs to be updated.
While this MR has this functionality basically working, it also has some uncomfortable edge cases (Moving multiple keyframes at once can cause unexpected behavior, some circumstances where the scene my be removed erroneously) and an increasing number of circumstances to check for that I believe that the design for the "solution" here might not be correct in the first place.
Here are some notes I've been taking as I've been thinking about and working on the issue. Some of these will be marked as long term if I think they're not important to get done right away for Krita 5.1, but should at least be worked toward.
- Storyboard data changes: Some parts of the storyboard code are made more complicated by the fact we are storing scene "duration" into the data of the storyboards and saving them out. We should remove the "duration" field, as the duration is simply the intrinsic element of the difference between start frames of the scene and the next scene (the exception being the last scene, which would need to be addressed.) IMO, this should happen immediately, since the current design seems error prone and adds a lot of cruft to the StoryboardModel class and anything else that might either need the duration of a scene or needs to edit the duration of a scene.
- [Long Term] Storyboard data should either be a keyframe channel or something else entirely: The current design of the storyboard data is both strangely connected to a layer's keyframe channels while also not adhering to the same design principles (not using the same basic class structure). This is probably the result of the fact that the GSOC project was happening while we were rewriting the keyframe channel class, so I'll chalk it up to unfortunate timing. We either need to change the way we think about storyboards (Note the Post Krita 5 document changes proposed, we might consider each board it's own "image", so-to-speak) or we should try to have it act by similar means.
- Should we be inferring meaning from timeline actions? Or do we simply need to give the user basic levels of scene management in the timeline docker? Perhaps the key observation from this is that trying to infer meaning from a users keyframe movements is not entirely wise. It could be the case that some users want to be able to manage scenes without any keyframe data that exists on the first frame of a scene, or that a user simply wants to move keyframes around without adjusting the storyboards at all. With this in mind, a possibly better solution would be to provide the user basic scene editing capabilities within the timeline docker so that the user can move scene start / end points manually if they need to be adjusted. This would arguably be simpler for the user and the developer, since there would no longer need to be any kind of "interpretation" of the actions. This may require the above "long term" goal to be addressed, since adding support for storyboard editing in the timeline would arguably be simpler by giving it the same interface.
- [Long Term] Timeline signals and events: It's worth noting that the current design of the signals works well for the current use case, but there's an argument to be made that we can reduce the amount of signal calls by trying to merge larger "meta" transactions into some kind of mini ledger. For example, instead of notifying everyone when a keyframe is "removed" and "added" multiple times in a swapKeyframe call, it might be nice for a simple ledger to exist that describes the entire history of actions that took place that are then sent in bulk. This would help solve problems such as responding to the user moving multiple keyframes at once, where we actually might want to respond to the whole collection of movement operations instead of reacting to each one individually. The subscriber to the signal could also use it to actually gleam usable information from said transactions, reducing the need to write special-exceptions to keyframeAdded / KeyframeRemoved slots like those that exist in this MR.
Anyway, those are my thoughts. I will continue working on this once Krita 5.0 development settles.