Outliner Improvements Final Report
Over the course of the summer I implemented everything from my proposal, with some additional features suggested by users and other developers. All of the code in my branch was accepted and committed after review from my mentors and others. Most features I developed were smaller in scale, with the design for synced selection requiring the most design and revisions to polish the behavior and code. Some of the work I did includes:
- Synced selection between the outliner and other editors (in both directions)
- Outliner selection operators (range, box, and keyboard walk selection of elements)
- Fixes to scrolling operators
- Drag and drop improvements for parenting objects
Since committing my branch, I have continued to maintain my code and add new features. I am also making plans with other developers for further improvements. The design tasks that I am hoping to implement are found here: https://developer.blender.org/T68338.
- My patch for review can be found here: https://developer.blender.org/D5388
- The branch (
soc-2019-outliner) where I committed all of my work over the summer can be found here: https://developer.blender.org/diffusion/B/history/soc-2019-outliner/
- Weekly reports: https://devtalk.blender.org/t/gsoc-2019-outliner-weekly-reports/7642
- Forum topics where I discussed ideas with and received feedback from the community:
Participating in the Google Summer of Code has introduced me to working as a group developing software for users. I have been writing code for many years now, with some of my projects being useful to people, but participating on a larger scale with a mature project has taught me valuable skills.
A challenge I found with working on a team was managing priorities. During this summer, development for Blender 2.80 was coming to a close, with multiple release candidates and important bug fixes. It was during this time that I found myself ready for review on some of my code. I had to be patient (Helpful reviews did come!), developing smaller fixes while I waited. I understood that getting the release of 2.80 stable quickly was more important than reviewing my syncing code, but it took some time for me to realize that I could move on and develop other things while I waited.
Most features that I developed are simple enough to understand by looking at a few functions in the source code. Selection syncing is more complicated. I am leaving some documentation here so others can refer to the implementation in the future, and understand why some decisions were made. Here is the original syncing design document.
Synced selection is controlled via a toggle in each outliner, enabled by default. No selection or activation operations are synced with synced selection disabled; selection is isolated to the outliner. When synced selection is enabled, any selections are synced to the current view layer and Sequencer. Selections from the Sequencer or 3D View are be synced to each outliner. Outliner selections do not sync to other Outliner editors. Objects, edit bones, pose bones, and sequences are the only types of data synced.
Each Outliner has a flag to determine which types of objects need to be synced. An additional flag stored in the Window Manager is tagged by operators, which is later copied to individual outliner syncing flags.
In the WindowManager is the flag
outliner_sync_select_dirty, which can be set to any combination of
These flags are exposed through functions (in
ED_outliner_select_sync_from_object_tag(bContext *). Any operator that modifies selection (3D view selection, object add, undo, redo, sequence select, etc.) needs to tag the respective types of data to be synced.
The functions that deal with selection syncing are found in
Syncing is done lazily on Outliner draw; if no outliners are visible, no syncing will occur to prevent unnecessary processing. When an outliner draws (
outliner_draw.c) it first checks if the
outliner_sync_select_dirty flag is set. If the flag is dirty, that means a selection changed in the Sequencer or 3D View. The flag will be copied to each outliner's
sync_select_dirty flag. Then the WindowManager flag is cleared.
Following that, the outliner will check if it's
sync_select_dirty flag is set. If set, a sync operation occurs. This iterates over the tree and syncs selection from objects, edit bones, pose bones, or sequences, depending on what selection events have occurred. More details on this are below. Then the outliner is drawn.
For outliner operators that change selection,
ED_outliner_select_sync_from_outliner(bContext *, SpaceOutliner *) must be called to sync the selection to the proper editor.
Determining Sync Types
To determine which types of data to sync, a few factors are brought into consideration:
- The current interaction mode
- The outliner display mode (Sequencer or other)
sync_select_dirtyflag (for syncing to an Outliner)
This ensures that only one type of data is synced per operation.
Some design decisions have been made that aren't required for syncing, but hopefully make the process more intuitive for end-users.
- When syncing to an outliner, elements that cannot be synced are deselected. If a Collection were selected in the outliner, and an object is selected in the 3D view, the Collection will be deselected in the Outliner. This is to only show the newly selected data as selected in the Outliner.
- Activation does not occur when synced selection is disabled. This can be useful for managing collections, setting parents, and other operations that you don't want to disrupt the 3D view selection.
- Objects can be linked to multiple collections. When selecting such an object from the 3D view, both instances are selected in an Outliner. When selecting one of these instances from within an Outliner, only one instance is selected.
- Outliner selection is not synced to other Outliner editors. While this is simple to implement, not many users have multiple Outliner editors open at one time, and those who do may find it more useful to keep distinct selection in each Outliner.