1
1

Compare commits

...

236 Commits

Author SHA1 Message Date
723d05070a Outliner: Includes cleanup 2019-08-16 11:21:34 -06:00
0e2b56ed71 Merge branch 'master' into soc-2019-outliner 2019-08-16 09:32:29 -06:00
d156139cbc Merge branch 'master' into soc-2019-outliner 2019-08-15 16:16:51 -06:00
28ee7e60c5 Outliner: increase contrast of selected and active highlights 2019-08-14 21:06:47 -06:00
8c3b3a982b Outliner: Don't allow duplicates for merge search
Only show one item for each subtree element in a merge search popup.
Selecting an element from the popup that has multiple instances in the
subtree will select the first instance in the tree.
2019-08-14 20:26:22 -06:00
90e07364ac Outliner: Clear dirty flag after sync from outliner
This prevents syncing to the outliner on draw which deselects
non-syncable data like mesh data and collections.
2019-08-14 15:06:54 -06:00
6e11d5f6fc Outliner: Activate on range select with no active element
If no active element exists in the outliner, activate the cursor
element instead of only selecting.
2019-08-14 15:04:37 -06:00
5d52524b96 Outliner: Remove parent set popup menu for specific types
Removes the popup for setting the parent to curves, lattices, and
armatures. It makes more sense from an outliner perspective to set
the parent to objects only.
2019-08-14 14:28:22 -06:00
99bf3d275c Outliner: Openclose fixes
Remove walk in / walk out support for walk navigation. Now left
and right arrow keys only close and open outliner element subtrees.

Fix click+drag on disclosure triangles not behaving as expected.
Now the dragged elements will be either opened or closed, using the
state of the first click+dragged element.
2019-08-14 14:16:26 -06:00
705b4f2ef0 Outliner: Don't sync outliner selection to other outliners 2019-08-14 14:13:25 -06:00
d934a78d10 Outliner: Sync select toggle tweaks
Move the toggle lower in the popover as this toggle is not as
important. Also use a checkbox rather than button.

The toggle is still drawn as a button with an icon when the outliner
is in sequence display mode, as the filter popover is not drawn
in that mode.
2019-08-14 13:43:02 -06:00
9494c3df53 Merge branch 'master' into soc-2019-outliner 2019-08-14 11:58:22 -06:00
e088ee55f7 Outliner: Use GSet for select sync from outliner 2019-08-14 11:56:09 -06:00
16c18c5bfb Outliner: Comments cleanup 2019-08-13 21:50:34 -06:00
ec3cd8d400 Outliner: Fix selection syncing for edit bones
Fixes selection syncing from outliner for edit bones not tagging
for updates.
2019-08-13 21:19:46 -06:00
919d1b53ae Outliner: Fix selection syncing of linked items
When an item was linked to multiple collections, an outliner select
would sync the selection state of the last instance, deselecting
even if a previous element was selected.

Selection syncing from the outliner now maintains lists of selected
objects and bones to prevent syncing errors.
2019-08-13 21:04:17 -06:00
dbed7dba22 Outliner: Use interaction mode to restrict syncing
Use the current interation mode to prevent syncing from getting out
of sync. Because the bone elements shown in object mode are not the
same elemens as in pose or edit mode, it is necessary to only sync
bones in bone edit or pose mode.
2019-08-10 22:25:36 -06:00
7e7b073712 Outliner: Deselect data elements on selection sync
Outliner items like mesh data and collections cannot be synced
to the 3D view, but it is still useful to have them selected in
the outliner. When syncing selection to the outliner, it makes
sense to deselect these data elements.
2019-08-09 22:45:54 -06:00
340fc634ad Outliner: Comment and includes cleanup 2019-08-09 14:10:36 -06:00
1ed65f1cbd Merge branch 'master' into soc-2019-outliner 2019-08-09 13:28:35 -06:00
f4373aa3a7 Merge branch 'master' into soc-2019-outliner 2019-08-08 15:53:54 -06:00
0683b716a0 Cleanup: versioning comment for outliner syncing 2019-08-08 13:59:58 -06:00
dd9dbc05ee Merge branch 'master' into soc-2019-outliner 2019-08-08 13:10:34 -06:00
aaf3ed3db0 Pass active data as pointer
Check tselem type before checking if type should be synced when syncing
from the outliner
2019-08-07 21:22:33 -06:00
dae8db68e9 Merge branch 'master' into soc-2019-outliner 2019-08-07 18:45:55 -06:00
d030770449 Pass outliner type as a pointer
Also adjust if statements not to keep checking outliner types
when that type has been disabled.
2019-08-07 22:17:05 +10:00
48679697e5 Merge branch 'master' into soc-2019-outliner 2019-08-07 22:02:30 +10:00
22fea4852f Only notify on syncing specific types of data 2019-08-06 23:29:34 -06:00
fd89431861 Tag depsgraph on pose bone sync only if changed 2019-08-06 23:25:29 -06:00
c08ac7562c Fix crash on editbone syncing 2019-08-06 23:25:00 -06:00
367a944541 Rename sync select set type functions for more clarity 2019-08-06 23:03:37 -06:00
6c52eb2183 Restrict sync types on outliner select
Use outliner display mode to determine to sync object and bones or
just sequences. This could be expanded later to determine the
current selection mode for more granularity in objects, edit bones,
and pose bones
2019-08-06 22:57:47 -06:00
1760a6e8cd Add comments and organize ED_outliner functions 2019-08-06 22:35:33 -06:00
67f9c22f54 Reorganize code to better show to and from outliner syncing 2019-08-06 22:23:50 -06:00
c2b752b268 Prevent getting active data during syncing
Store active data in a struct before syncing
2019-08-06 22:22:06 -06:00
3da5106dac Use sync select dirty flag to restrict syncing types
Use the sync select dirty flag and outliner display mode to determine
which types to sync to the outliner.
2019-08-06 21:48:44 -06:00
2a4ab7ed9a Outliner Merged object search: Simplify memory free callback
Rather than use custom callback, use MEM_freeN
2019-08-06 17:18:27 -06:00
2608109308 Preserve existing dirty flags when flagging outliners 2019-08-06 10:15:12 -06:00
6bf5959fa2 Avoid getting scene & view layer for each call to outliner_sync_selection_from_outliner 2019-08-07 01:33:18 +10:00
47b478eb68 Rename vars 2019-08-07 01:23:21 +10:00
52acbc43f0 Merge branch 'master' into soc-2019-outliner 2019-08-06 22:03:33 +10:00
e4516299a0 Merge branch 'master' into soc-2019-outliner 2019-08-06 15:41:32 +10:00
5a93b1a51c Outliner: cleanup outliner selection syncing function name
Cleanup function names for clarity
2019-08-05 21:00:22 -06:00
63074fc889 Outliner: Refactor synced selection to use wm flags
Starting point to sync based on type to optimize syncing for
larger scenes. Also cleanup from review.
2019-08-05 20:49:44 -06:00
fccf729f09 Outliner: ensure all outliners start drawn synced
Adds flag setting for versioning and space duplicate and new
to sync each outliner on first draw and set synced selection to
the state of the duplicated outliner, or toggled on if creating
a new outliner.
2019-08-05 12:35:26 -06:00
6f208b9024 Merge branch 'master' into soc-2019-outliner 2019-08-05 10:33:33 -06:00
364e7e0849 Outliner: Cleanup walk select and syncing code 2019-08-03 14:22:17 -06:00
e4f23f7e17 Cleanup: Comments in collection parent activation 2019-08-03 14:01:42 -06:00
e55e23a9d5 Datadropper: Cleanup
Renamed area_current to cursor_area for clarity
2019-08-03 13:59:45 -06:00
7eb5f9501a Merge branch 'master' into soc-2019-outliner 2019-08-03 13:38:56 -06:00
ed35d00fc2 Outliner: Fix openclose keymap 2019-08-02 22:07:53 -06:00
9a9924894c Merge branch 'master' into soc-2019-outliner 2019-08-01 18:37:21 -06:00
c8c85907b4 Outliner cleanup: Move give base under cursor to utils
Moving eyedropper function from select to utils for better code
organization.
2019-08-01 17:37:42 -06:00
5283f90bd0 Outliner cleanup
Cleanup and comment code more thoroughly after initial branch
review. Renamed SO_SYNC_SELECTION to SO_SYNC_SELECT.
2019-08-01 17:13:10 -06:00
091736088e Merge branch 'master' into soc-2019-outliner 2019-08-01 16:10:44 -06:00
2120a65391 Outliner: Open Scene list elements by default
Ensures that Scenes in the outliner scene display mode start opened.

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Outliner: Add active element theme color

Adds a themable color for the outliner's active elements in both light and default themes

Outliner: Active element

Initial implementation for active elements. Currently works for select and extend selection

Merge branch 'master' into soc-2019-outliner

Outliner: Utils function to find active element

Searches tree and returns active TreeElement

Outliner: Add range select to keymap

Changes keymap for outliner.item_activate
ctrl: extend
shift: range
alt: recursive
ctrl+alt: recursive extend

Merge branch 'master' into soc-2019-outliner

Outliner: Utils function is element visible

Outliner: Add range select

Adds range select to outliner_activate.
Range select is based on the active element and the clicked element.
If no active element is visible, report an error

Outliner: Click and drag to box select

Allows tweak event for box selection from the left gutter of the outliner.
If the gutter is clicked, everything is deselected

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Revert "Outliner: Open Scene list elements by default"

This reverts commit a3448a9eef.

I accidentally included the submodules in the commit. Won't happen again!

Outliner: Fix scene elements closed by default

I committed this earlier but accidentally committed the submodules alongside it.

Outliner: Remove range select restrictions

Removes restrictions for range select requiring a visible active element.
Now if no active element is visible the shift+clicked element is set as active and selected.
This way no warnings need to be reported.

Also silenced some warnings

Outliner: Allow box select from any empty space

This allows click and drag box select from anywhere except for name
and icons of elements. Currently the restriction toggles are a valid
locaion to select from. Could remove if it becomes an issue

Outliner: Add walk select operator

Adds a walk select operator to the outliner. Currently only up
and down walk are supported, opening and closing and walking left
and right will be added later.

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Outliner: Fix memroy error in walk select

Didn't close an EnumPropertyItem with NULL

Merge branch 'master' into soc-2019-outliner

Outliner: Finish walk select

Adds walk in and out for walk select (left and right arrows)
If an element is closed, walk in will open the element. If
the element is open, left will close it. Otherwise left moves the
active element to the parent.

Merge branch 'master' into soc-2019-outliner

Outliner: Fix opening scenes by default

Keeping `sce == scene` for files with many scenes and having too many
open becomes unmaneageable.

Outliner: Cleanup active element

After discussion with Campbell, I realized that some ways I was using
active elements did not fit with Blender's way of things. Like box select
making the root of the tree active if no active element existed. These
issues are fixed, in addition to using the already-present `active`
Theme struct member.

Outliner: Cleanup range and box select

Cleanup properties, keymap, code styling, and descriptions

Outliner: Fix crash on modifier key click in empty space

I changed this line earlier, I think while implementing box selection.
Changing it back to what it was before I modified it solved the issue.

Outliner: Fix walk select error on open leaf elements

In the outliner, leaf elements like light or material data do not
show a disclosure triangle. However, they can still be toggled
with a click or the openclose operator. This led to the walk select
attempting to walk down another level in the tree.

This could be fixed in the toggle open/close functions as well, but
it seems to address it in walk select seemed simpler as this is
the only area affected.

Fix: Use correct icon for armature deform constraint

Use constraint icon rather than modifier icon for consistency

Outliner: Draw constraint icons

Draws constraint icons in the outliner for bones and objects. The
only icon that has an issue is the Action constraint icon, because
it doesn't have a specific constraint icon, so it is drawn white
instead of blue.

At first I tried to replicate the code for modifier icons, then
I found a solution using `te->directdata` that worked for both
objects and bones. It works well enough, not sure if that simpler
solution should be used for modifiers too.

Outliner: Redraw on constraint reordering

Rather than restricting which constraint actions redraw the outliner,
all will (similar to modifiers). This will redraw on constraint
reorder

Merge branch 'master' into soc-2019-outliner

Outliner: Add sync selection property

Adds a toggle to each outliner for synced selection

Outliner: Remove negative from sync selection

Removing because it was behaving strangely. I might not entirely
understand what `negative_sdna` does

Outliner: Add dirty flag

This dirty flag is to indicate whether an outliner needs to sync
its selection state with the active view layer before redrawing

Outliner: Add synced selection

This implementation is to see how syncing will be done, to be redone
later in a more general way. Right now each operator must explicitly
sync the selection.

Outliner: Refine synced selection

Any selection event that uses ED_object_base_select will now
mark the outliners as being dirty. When an outliner draws and is
dirty with synced selection enabled, it will sync its selection
state with the view layer.

More work still needs to be done. This may not be the best way
to implement it (selections from scripts won't be tracked). Also,
selection from the outliner isn't perfect.

Merge branch 'master' into soc-2019-outliner

Outliner Visibility: Add Invisible filter

This adds an object invisible filter to the outliner to only show hidden
or disabled objects in the outliner. In large scenes, it is often
difficult to locate hidden objects in the outliner to show them again.
This invisible filter makes it easier.

Outliner: Show enable/disable button for constraints

This adds the restriction icon for constraints in the outliner so
they can be enabled/disabled similar to modifiers.

It also moves the icon definition to RNA from the UI template for
the constraints in the properties editor.

Outliner: Add modifier keys to box select

Adds shift for add and ctrl for subtract, matching the 3D view
default keymap.

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Outliner: Versioning for active element theme change

It doesn't have a version bump condition currently to always apply
the theme during the summer of code

Outliner: Fix TreeStore loading in textbutton edit mode

Fixes incorrectly added the TSE_ACTIVE flag field after TSE_SELECTED
because it logically made more sense there. Old files were loading
with each tree element in textbutton edit mode. This addresses that
and other issues with mismatches on TreeStoreElem flags.

Outliner: Don't adjust horizontal scroll on show active

The show active operator tried to scroll the outliner
horizontally to show the active object. On wide outliners this
caused a jittery redraw on mousemove. When the outliner
was more narrow, repeating the operation also caused
unexpected jittery redraws.

Merge branch 'master' into soc-2019-outliner

Outliner: Sync selection state on sync selection toggle

When turning on synced selection, sync the selection. Previously
this required clicking in the outliner or doing a 3D view selection
operation.

Merge branch 'soc-2019-outliner' of git.blender.org:blender into soc-2019-outliner

Outliner: Silence warning on visibility

Missing a break within a switch.

Eyedropper: Support datablock picking in outliner

This adds support for picking datablocks from the outliner with the
eyedropper tool.

This requires changing the region the UI tooltip is drawn in by
tracking when the mouse moves to a different area on the screen.
By doing this the draw callback can be reset for each new area the
eyedropper enters.

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Revert most of "Outliner: Refine synced selection"

This reverts the majority of commit
ad1ff2b601.

Rather than modifying ED_object_base_select to need the
view layer, use a global instead (for now)

Outliner: Add sync selection flag to main

The is_sync_select_dirty flag will be set after outliner and
3D viewport selection events to indicate a sync needs to occur.

Outliner: Enable synced selection by default

Mark outliners as dirty and enable synced selection for new
outliners. Also apply in versioning.

Outliner: Redraw 3D view after syncing selection

After deselect all in the outliner, the 3D view needs to be redrawn.
Also fix some syncing edge cases

Outliner: Redo synced selection dirty outliner implementation

The previous implementation assumed each selection type was identical
and synced each outliner with the 3D view. This had flaws because
hidden objects can be selected in the outliner, and it would be impossible
to know whether or not to keep them selected when syncing. To work around
that and other cases, this implementation does two things:

1. After any 3D view selection, sync selection flags with an outliner.
After syncing, a clean outliner is stored. Then the other outliners
are marked as dirty, to be synced from the clean outliner.

2. After an outliner select, that outliner is set as clean and the
other outliners are marked as dirty to be synced from.

More work is needed to support all outliner selection operations,
as well as properly supporting extending selections from the 3D
view. However, the underlying code for selection syncing should now
support the edge cases that the other implementation failed to
support.

Merge branch 'master' into soc-2019-outliner

Synced Selection: Fix syncing not working

Removing some changes that were supposed to address extending
the selection, but they were preventing the replace selection
from behaving properly.

Synced Selection: Sync outliner selections to view layer

Outliner select operators now flush their selections to the
active view layer when synced selection is enabled.

Merge branch 'master' into soc-2019-outliner

Outliner: Only draw active highlight when syncing selection

When synced selection is off, it makes no sense to draw
active highlights, especially because they may be out of
sync from view layer active highlights

Merge branch 'master' into soc-2019-outliner

Synced Selection: Sync active objects between outliner and view layer

This adds the syncing of active elements. When synced selection is off
and elements are selected, no activation or selection will occur.
When synced selection is enabled, active bases will be synced
in both directions between outliner and view layer.

Currently some issues still exist, like selecting a collection
will mark it active.

Outliner: Select active on walk select with no elements selected

Rather than actually walking the selection down from the active
element on walk select, the operator now only selects the active
element in the outliner.

Outliner: Fix walk selection wrapping and other issues

This prevents walk selection from wrapping around from the last
to the first tree element. Additionally, if the active tree
element is within a closed subtree, walk select will move the
active element to the first visible parent.

The operator code is also simplified and slightly optimized.

Outliner: Fix tree building not setting parents properly

When the scenes view tree was built, the parent for view layers
and objects were not set properly (either NULL or incorrect
parent), causing walk select to fail. Now the proper parents are
set.

Not sure if there was a reason why the wrong parent was set for
view layers before.

Outliner: Add extend selection to walk select

Walk select now extends the selection when shift is pressed.
This implementation works well, though if there are existing
selections in the tree the behavior may not work as expected.
This could be improved on in the future if that is a problem.

Merge branch 'master' into soc-2019-outliner

Outliner: Remove ctrl+click to rename

This conflicts with ctrl+click to extend selection, and is not
conventional. F2 and double click still function to rename
elements in the outliner.

Outliner: Fix range selection on active element

Range select on active element was selecting down the entire tree
because there was no element to stop at. This is resolved by
not doing a range select when the cursor element and the active
element are the same.

Outliner: Move sync_select_dirty_flag to new file

Adds `outliner_sync.c` for the global rather than storing in Main.

Outliner: Move selection syncing functions to outliner_sync.c

This is just for organization. Also fixes a small error when
outliner select/deselect all still synced when selection syncing
was disabled.

Outliner: Fix range select when active element is not selected

When the active element was not selected and range select
was used, it would become selected and the range select would
execute. A more intuitive behavior is to simply select the clicked
element.

Also optimized the outliner_is_element_visible utility function

Merge branch 'master' into soc-2019-outliner

Outliner: Fix range select sometimes leaving hidden elements selected

The range select opearator sometimes would leave other elements
selected when changing the active element. This is fixed by
clearing the selection each time the operator runs.

Merge branch 'master' into soc-2019-outliner

Outliner: Draw more sequencer icons

Not all of the sequencer icons had been added to the outliner.
Some are still drawing with editor/modifier colors so they will
need their own icons. Or some other code workaround.

Outliner: Sync selection from sequencer

Sequencer selection operators now sync to outliners. Still needs
to sync the other direction

Outliner: Draw correct scene icon

Was drawing incorrect icon for scene

Outliner: Sync selection from outliner to sequencer

Outliner selection events now sync to the sequencer. Still need
to support active strips

Outliner: Sync active sequences between outliner and sequencer

Active sequences are now synced on selection

Outliner: Fix crash on range select when no active element exists

The old code incorrectly assumed that an active element always
existed. The fix is to set the cursor element to active when
no active element is found.

Synced Selection: Merge functions

Merged the sequence and base syncing functions together to
simplify and to make adding pose and edit bone syncing easier.
Also reduces the number of times the tree is looped over.

Outliner: Sync edit and pose bone selection state

Syncs selection to and from outliner for bones in both modes.

The code for pose bones is acceptable, but edit bones is quite
the mess. Something more intelligent needs to be thought of here.

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Outliner: Activate elements on walk select

Rather than just setting flags, activate outliner elements
to support toggling modes. This still needs some work while in
synced selection mode. Outside of synced selection it works
well

Merge branch 'master' into soc-2019-outliner

Outliner: Move active element code

Moves code for setting active element to activate function
rather than select function as this makes more sense

Outliner: Support selecting other objects when in edit/pose modes

When selecting in the outliner, rather than activating other
elements when in edit or pose mode, just select. This is useful
for selecting other objects while in edit/pose modes for adding
parents, hooks, etc.

Outliner: Fix setting active when in edit mode

Fixes some small issues with setting active elements

Merge branch 'master' into soc-2019-outliner

Merge branch 'master' into soc-2019-outliner

Outliner: Utils made outliner_find_active more general

Rather than only searching for active, now search for element with
matching flag.

Outliner: Rewrite walk select

Rather than basing walk select on active flags, use a new TSE_WALK
flag to navigate. Also cleaned up and simplified code.

Outliner: Fix setting of active element from the outliner

The active element was being synced, which incorrectly failed
when clicking on object data and other non-base elements in the
outliner. Now it leaves activation to operators in the outliner
rather than syncing to avoid code duplication.

Merge branch 'master' into soc-2019-outliner

Outliner: prevent bone selection when sync select disabled

More refinements to the synced selection code

Outliner: Cleanup sync code

Removed some commented code

Outliner: Improve walk select

Now that walk select doesn't start from active, some selection
operators and syncing needed to set the walk element. So after
some select operators, set the walk element alongside the active
element

Outliner: Remove warnings

Left a few unused variables from removing old code

Keymap: Simplify outliner select keymap

Changed extend default and simplified the keymap

Outliner: Disable synced selection in certain modes

Certain display modes don't make sense, or don't work well for
selection syncing. This disables syncing in Blender Libraries,
Data API, and Orphans view.

Revert "Keymap: Simplify outliner select keymap"

This reverts most of commit 210600e7f6.

Outliner: Support multiple objects for parenting

Now parents multiple objects in the outliner on drag and drop.
This only works for setting an object as the parent, not for
armatures, lattices, etc. Will be improved on.

Outliner: Always do object parenting

Outliner: Support multiple selected objects for parent clear

Clear parents for all selected objects on drag and drop

Merge branch 'master' into soc-2019-outliner

Collections: Update active collection after visibility restriction

When changing viewport visiblity or restriction change the active
collection. This replicates the behavior of excluding the active
collection, which sets the first non-excluded parent as active.

This required a function to recursively check parents for the
visiblility restrictions.

Merge branch 'master' into soc-2019-outliner

Outliner: Set active camera on camera data activate

Allow setting the active scene camera on camera data activate.

Not sure if all the depsgraph and event notifier calls are needed.
Tested removing some and it still worked.

Outliner: Fix crash on duplicating scene

The function to determine if a collection was hidden was missing
a check to see if the layer collection was not null.

Outliner: Redraw on scene camera change

This appears to be a redraw on any change in the scene..
wonder if there is a better way.

Merge branch 'master' into soc-2019-outliner

Outliner: Prevent scroll page from leaving view bounds

The page up/down operator to scroll the tree could go past the
bounds of the tree leading to jumpy redraws. This prevents the
operator to go outside the bounds of the area.

Merge branch 'master' into soc-2019-outliner

Outliner: Show active improvements

Prevent the show active operator from scrolling beneath the
allowed scrolling range. This removes jumpy redraws after the
operator executes.

The horizontal centering is difficult, because the elements
outside the view of the outliner do not have the xend properly set
and the max width of the outliner is not properly calculated.
This means it is not possible to center the x position while
keeping the view in range of scrolling.

This could be resolved by drawing the outliner after setting the y
position, but that is not an ideal solution.

Outliner: Allow clicking on row icons

The feature to click on row icons was removed (presumably because
the icons now draw stacked with a number, rather than individually).
This brings back support for clicking because the benefits of
clicking on the icon without opening the element outweighs the con
of not being able to select grouped elements. A solution for that
is being worked on.

Outliner: Search recursively for icons in row

Rather than searching just the child list, search recursively
down the tree to allow clicking on all icons.

Outliner: Fix find item at x

Now that the icons are displayed for the entire subtree, the
condition to not look past the cursor X position caused errors.
Removed and the function behaves as expected.

Outliner: Draw highlights for icons in row

This draws icon highlights when the row icons are hovered.

Merge branch 'master' into soc-2019-outliner

Outliner: Rename tree element flag

Renamed from MULTI to MERGED now that I see the real name in the
code

Outliner: Show menu when clicking on aggregated iconrow icons

This is still a work in progress. The code needs to be better
and the behavior could use some improvement. It works okay for
now though.

Merge branch 'master' into soc-2019-outliner

Outliner: Use existing function to get unique index for element type

Just code cleanup for merged element search menu

Outliner: Draw icons in merged icon select menu

Get icon for each tree element when listing the menu

Outliner: Clear search on creation of merged element search menu

Rather than showing the last searched or selected element name
in the search button, clear each time the menu is created so
all the items are shown by default.

Outliner Cleanup: Move merge search to outliner_tools.c

Moving to a different file because the search is a menu and that
fits in better with the code there compared to the select code.

Outliner Cleanup: Finish renaming multi object to merged

Cleaned up the select code to use the word merged rather than
multi object for consistency

Outliner: Merged icon select popup UI tweaks

Adjusted some spacing and did some cleanup to the code

Outliner comment cleanup

Merge branch 'master' into soc-2019-outliner

Outliner: Fix merge search menu not showing all children

The menu was not searching over the entire subtree of the
collapsed element, but it also needed information of the
parent element and type, so a struct and memory allocation were
required to pass all of the data into the popup menu.

Outliner: Fix merge element search from finding incorrect items

When selecting aggregated collections (for example) the search
menu would show many other types of data (vertex groups, materials,
modifiers, etc.) This fixes that issue.

Merge branch 'master' into soc-2019-outliner

Outliner: Adjust data icon drawing

The icons drawn on the iconrow were brighter than the expanded
icons. This changes the color to be identical.

Merge branch 'master' into soc-2019-outliner

Outliner: Move sync selection toggle to filter popover

Moved the toggle to the popover. When in sequences view the
filter popover does not show, so the toggle is drawn on the header
in that case.

Outliner: Merged Element Search Menu Cleanup

Simplified the struct passed to the popup menu

Outliner: Fix coordinates setting incorrectly on iconrow

Iconrow coordinates were set incorrectly sometimes. It was a bad
condition check.

Outliner: Draw vertex group icons

Outliner cleanup: Disclosure triangle coordinate check

This shouldn't need to check if the element is am iconrow element
because no iconrow elements are found until the call to
`outliner_find_item_at_x_in_row`.

Outliner: Cleanup merge search menu

Moved the struct out of the intern file to simplify and group
related code better. It was easily possible to move all the
menu code to `outliner_tools.c` so this makes more sense.
Also leads to a cleaner outliner element activate function.

Outliner: Support click+drag for toggling disclosure triangles

This reworks the openclose operator for toggling disclosure
triangles. Rather than mapping to `Enter` by default, it supports
left click and left tweak events. This allows click+drag over
elements in the tree to open or close levels. Once the click+drag
is started, only elements on that level in the outliner will open
or close.

This removes the toggling from `outliner_select.c` which adds more
clarity to the activate function.

Outliner: Cleanup outliner_select.c

Remove the unnecessary toggle function which involved duplicated
code, and move the check for restrict columns to the utils file
as it is used in multiple files.

Merge branch 'master' into soc-2019-outliner

Keymap: Remove recursive select from outliner

Removes alt and alt+ctrl from outliner for recursive select
as there is a context menu option for this, and alt+click can be
taken globally by the emulate 3 button mouse option.

Outliner fix openclose recursive not working as expected

The openclose all operator would not close the upper element, nor
would it work on the outermost collections of a scene. Now the
recursive open all option will work as expected, opening all of
an element's children, and the element itself, or closing
the element and all of its children.

Outliner: Add open/close all children to walk navigation

When pressing Shift and left or right arrow, expand or collapse
all child elements in walk navigation.

Outliner: Fix item openclose

Rather than just switching between open and close when toggling
all children, first check if any children are closed when the
item is open. If so, extend all the children first. This behavior
makes more sense.

Merge branch 'master' into soc-2019-outliner

Outliner: Improve click and drag for openclose

This adds the ability to click and drag over a disclosure triangle
and immediately drag back over it to close it. Previously it
required opening the next element before closing the first opened
element because of the way the operator stored the previously
toggled disclosure. This makes the operator more easy to use and
understand.

Outliner: Fix small issues in walk navigation

After adding open/close features to walk navigation, a few small
issues appeared. This adds a few more checks to ensure a walk
or expand really occurs when the desired keys are pressed, rather
than expanding when a walk is desired.

Also moved the walking code to separate functions to make the
switch statement more clear to read.

Outliner: Cleanup item activate code

Removed the recursive operator property as it is no longer needed.

Outliner: Refactor show active to show all instances of object

Previously the show active operator opened the tree to show the
first instance of the active object. With collection linking,
the active object could be in multiple collections. This expands
the show active operator to expand all hierarchies that contain
the active object. The view will be centered on the first
active object in the outliner.

Outliner: small cleanup to show active

Merge branch 'master' into soc-2019-outliner

Outliner: Add set parent menu for multiple objects

Allow setting the parent for multiple objects to curves, lattices
and armatures from the outliner. This has a few issues still.

Keymap: Remove recursive property from outliner item activate

Merge branch 'master' into soc-2019-outliner

Keymap: Support F2 for rename in the outliner

Rather than use the F2 rename active object popup when in the
outliner, rename the active element. This allows renaming object
data, collection, and other non-object elements within the
outiner.

Outliner: Improvements to outliner parenting

Cleaned up the code for parenting to armatures, lattices, and
curves. The only downside of this method is the operator reports
will not function from the menu.

Outliner: small cleanup for show active

Outliner: Fix icons drawing over rename box

The iconrow icons were drawing as buttons, placing them above the
textbutton for item renaming. This reverts an older change which
broke the expected behavior.

Outliner: Basic outliner walk scrolling implementation

A staring point for outliner walk navigation scrolling. This
will scroll the outliner to keep the walk element in focus.

Outliner cleanup: openclose and scroll page

Simplify code and operator properties

Keymap: Simplify openclose keymap

Merge branch 'master' into soc-2019-outliner

Outliner: Add scroll view util function

Adds a scroll view utility function to be used for walk select
scrolling, pageup/pagedown scrolling, show active, and other
operators that scroll the outliner. The scroll view function
ensures the scroll amount does not go past the bounds of the
outliner, reducing redundant code in the operators.

Outliner: Use scroll view util function for walk scroll

Simplify the walk scrolling function by using the scrol view util
function

Outliner: Use scroll view util function for walk scroll

Simplify the walk scrolling function by using the scrol view util
function

Outliner: Cleanup scroll page and show active

Use scroll view util function to reduce complicated and
redundant code.

Merge branch 'soc-2019-outliner' of git.blender.org:blender into soc-2019-outliner

Outliner cleanup: Version control text

Not sure what VSCode did here. Cleaning up extra text.

Merge branch 'master' into soc-2019-outliner

Differential Revision: https://developer.blender.org/D5388
2019-07-31 22:44:24 -06:00
ca8086663c Outliner cleanup: Version control text
Not sure what VSCode did here. Cleaning up extra text.
2019-07-31 22:33:41 -06:00
1e037295d8 Merge branch 'soc-2019-outliner' of git.blender.org:blender into soc-2019-outliner 2019-07-31 22:32:20 -06:00
6fdad0afbc Outliner: Cleanup scroll page and show active
Use scroll view util function to reduce complicated and
redundant code.
2019-07-31 22:29:40 -06:00
bb795b2119 Outliner: Use scroll view util function for walk scroll
Simplify the walk scrolling function by using the scrol view util
function
2019-07-31 22:21:41 -06:00
7213f1775c Outliner: Use scroll view util function for walk scroll
Simplify the walk scrolling function by using the scrol view util
function
2019-07-31 19:19:06 -06:00
5dcbc32067 Outliner: Add scroll view util function
Adds a scroll view utility function to be used for walk select
scrolling, pageup/pagedown scrolling, show active, and other
operators that scroll the outliner. The scroll view function
ensures the scroll amount does not go past the bounds of the
outliner, reducing redundant code in the operators.
2019-07-31 19:00:40 -06:00
eb33e0369f Merge branch 'master' into soc-2019-outliner 2019-07-31 13:55:22 -06:00
389abca671 Keymap: Simplify openclose keymap 2019-07-31 13:51:21 -06:00
98af6c8ce3 Outliner cleanup: openclose and scroll page
Simplify code and operator properties
2019-07-31 13:51:05 -06:00
673323251c Outliner: Basic outliner walk scrolling implementation
A staring point for outliner walk navigation scrolling. This
will scroll the outliner to keep the walk element in focus.
2019-07-30 22:38:53 -06:00
18ac5447ad Outliner: Fix icons drawing over rename box
The iconrow icons were drawing as buttons, placing them above the
textbutton for item renaming. This reverts an older change which
broke the expected behavior.
2019-07-30 22:10:56 -06:00
3cbf9956e4 Outliner: small cleanup for show active 2019-07-30 19:23:27 -06:00
c4a4ba004a Outliner: Improvements to outliner parenting
Cleaned up the code for parenting to armatures, lattices, and
curves. The only downside of this method is the operator reports
will not function from the menu.
2019-07-30 17:35:27 -06:00
6267d647ae Keymap: Support F2 for rename in the outliner
Rather than use the F2 rename active object popup when in the
outliner, rename the active element. This allows renaming object
data, collection, and other non-object elements within the
outiner.
2019-07-30 13:38:08 -06:00
fe03e52227 Merge branch 'master' into soc-2019-outliner 2019-07-30 11:37:29 -06:00
c47018f603 Keymap: Remove recursive property from outliner item activate 2019-07-29 22:14:51 -06:00
65bad61cee Outliner: Add set parent menu for multiple objects
Allow setting the parent for multiple objects to curves, lattices
and armatures from the outliner. This has a few issues still.
2019-07-29 22:12:17 -06:00
598a4104a6 Merge branch 'master' into soc-2019-outliner 2019-07-29 10:55:16 -06:00
bdea5d6e01 Outliner: small cleanup to show active 2019-07-27 17:54:26 -06:00
e257f3c75e Outliner: Refactor show active to show all instances of object
Previously the show active operator opened the tree to show the
first instance of the active object. With collection linking,
the active object could be in multiple collections. This expands
the show active operator to expand all hierarchies that contain
the active object. The view will be centered on the first
active object in the outliner.
2019-07-26 21:29:10 -06:00
badb172cc3 Outliner: Cleanup item activate code
Removed the recursive operator property as it is no longer needed.
2019-07-26 17:18:30 -06:00
f2cc499a04 Outliner: Fix small issues in walk navigation
After adding open/close features to walk navigation, a few small
issues appeared. This adds a few more checks to ensure a walk
or expand really occurs when the desired keys are pressed, rather
than expanding when a walk is desired.

Also moved the walking code to separate functions to make the
switch statement more clear to read.
2019-07-26 15:33:56 -06:00
499c47a974 Outliner: Improve click and drag for openclose
This adds the ability to click and drag over a disclosure triangle
and immediately drag back over it to close it. Previously it
required opening the next element before closing the first opened
element because of the way the operator stored the previously
toggled disclosure. This makes the operator more easy to use and
understand.
2019-07-26 12:15:01 -06:00
6334ff86cb Merge branch 'master' into soc-2019-outliner 2019-07-26 10:47:34 -06:00
d50b8c0bfb Outliner: Fix item openclose
Rather than just switching between open and close when toggling
all children, first check if any children are closed when the
item is open. If so, extend all the children first. This behavior
makes more sense.
2019-07-25 20:38:59 -06:00
955c9dd98b Outliner: Add open/close all children to walk navigation
When pressing Shift and left or right arrow, expand or collapse
all child elements in walk navigation.
2019-07-25 20:38:08 -06:00
ec9dfb21d7 Outliner fix openclose recursive not working as expected
The openclose all operator would not close the upper element, nor
would it work on the outermost collections of a scene. Now the
recursive open all option will work as expected, opening all of
an element's children, and the element itself, or closing
the element and all of its children.
2019-07-25 16:06:02 -06:00
4b786c0a0c Keymap: Remove recursive select from outliner
Removes alt and alt+ctrl from outliner for recursive select
as there is a context menu option for this, and alt+click can be
taken globally by the emulate 3 button mouse option.
2019-07-25 15:49:46 -06:00
504542da09 Merge branch 'master' into soc-2019-outliner 2019-07-25 15:38:03 -06:00
d3c083f5be Outliner: Cleanup outliner_select.c
Remove the unnecessary toggle function which involved duplicated
code, and move the check for restrict columns to the utils file
as it is used in multiple files.
2019-07-25 15:36:08 -06:00
88a2c57827 Outliner: Support click+drag for toggling disclosure triangles
This reworks the openclose operator for toggling disclosure
triangles. Rather than mapping to `Enter` by default, it supports
left click and left tweak events. This allows click+drag over
elements in the tree to open or close levels. Once the click+drag
is started, only elements on that level in the outliner will open
or close.

This removes the toggling from `outliner_select.c` which adds more
clarity to the activate function.
2019-07-25 15:28:58 -06:00
f38c8b84b7 Outliner: Cleanup merge search menu
Moved the struct out of the intern file to simplify and group
related code better. It was easily possible to move all the
menu code to `outliner_tools.c` so this makes more sense.
Also leads to a cleaner outliner element activate function.
2019-07-23 19:59:02 -06:00
e1af790d2d Outliner cleanup: Disclosure triangle coordinate check
This shouldn't need to check if the element is am iconrow element
because no iconrow elements are found until the call to
`outliner_find_item_at_x_in_row`.
2019-07-23 19:50:38 -06:00
e2174037c6 Outliner: Draw vertex group icons 2019-07-23 19:05:13 -06:00
421b0bc443 Outliner: Fix coordinates setting incorrectly on iconrow
Iconrow coordinates were set incorrectly sometimes. It was a bad
condition check.
2019-07-23 18:56:53 -06:00
70dd380d72 Outliner: Merged Element Search Menu Cleanup
Simplified the struct passed to the popup menu
2019-07-23 13:34:01 -06:00
27da9edb1d Outliner: Move sync selection toggle to filter popover
Moved the toggle to the popover. When in sequences view the
filter popover does not show, so the toggle is drawn on the header
in that case.
2019-07-23 12:04:39 -06:00
006c8add7b Merge branch 'master' into soc-2019-outliner 2019-07-23 11:23:34 -06:00
8f37592666 Outliner: Adjust data icon drawing
The icons drawn on the iconrow were brighter than the expanded
icons. This changes the color to be identical.
2019-07-23 11:21:54 -06:00
6ac50f4bea Merge branch 'master' into soc-2019-outliner 2019-07-22 11:24:04 -06:00
b6405d001a Outliner: Fix merge element search from finding incorrect items
When selecting aggregated collections (for example) the search
menu would show many other types of data (vertex groups, materials,
modifiers, etc.) This fixes that issue.
2019-07-20 20:58:32 -06:00
b22c84d780 Outliner: Fix merge search menu not showing all children
The menu was not searching over the entire subtree of the
collapsed element, but it also needed information of the
parent element and type, so a struct and memory allocation were
required to pass all of the data into the popup menu.
2019-07-20 17:22:24 -06:00
927ffd4a52 Merge branch 'master' into soc-2019-outliner 2019-07-20 16:22:31 -06:00
3958c90871 Outliner comment cleanup 2019-07-19 15:31:36 -06:00
229578c9e5 Outliner: Merged icon select popup UI tweaks
Adjusted some spacing and did some cleanup to the code
2019-07-19 14:50:50 -06:00
3997ccdb73 Outliner Cleanup: Finish renaming multi object to merged
Cleaned up the select code to use the word merged rather than
multi object for consistency
2019-07-19 13:56:16 -06:00
807f95bf7a Outliner Cleanup: Move merge search to outliner_tools.c
Moving to a different file because the search is a menu and that
fits in better with the code there compared to the select code.
2019-07-19 11:34:36 -06:00
3d99c71837 Outliner: Clear search on creation of merged element search menu
Rather than showing the last searched or selected element name
in the search button, clear each time the menu is created so
all the items are shown by default.
2019-07-19 10:56:18 -06:00
8184c39ca7 Outliner: Draw icons in merged icon select menu
Get icon for each tree element when listing the menu
2019-07-19 10:42:13 -06:00
6513d55636 Outliner: Use existing function to get unique index for element type
Just code cleanup for merged element search menu
2019-07-19 10:33:28 -06:00
8637d8dcb3 Merge branch 'master' into soc-2019-outliner 2019-07-19 10:13:38 -06:00
8f2c296e22 Outliner: Show menu when clicking on aggregated iconrow icons
This is still a work in progress. The code needs to be better
and the behavior could use some improvement. It works okay for
now though.
2019-07-18 22:17:16 -06:00
cd0e42c065 Outliner: Rename tree element flag
Renamed from MULTI to MERGED now that I see the real name in the
code
2019-07-18 22:15:58 -06:00
cd00f29061 Merge branch 'master' into soc-2019-outliner 2019-07-18 11:54:49 -06:00
eed6d1dcf1 Outliner: Draw highlights for icons in row
This draws icon highlights when the row icons are hovered.
2019-07-18 11:53:11 -06:00
1becd16042 Outliner: Fix find item at x
Now that the icons are displayed for the entire subtree, the
condition to not look past the cursor X position caused errors.
Removed and the function behaves as expected.
2019-07-18 11:50:56 -06:00
1986efe44d Outliner: Search recursively for icons in row
Rather than searching just the child list, search recursively
down the tree to allow clicking on all icons.
2019-07-17 22:53:24 -06:00
f7310fae94 Outliner: Allow clicking on row icons
The feature to click on row icons was removed (presumably because
the icons now draw stacked with a number, rather than individually).
This brings back support for clicking because the benefits of
clicking on the icon without opening the element outweighs the con
of not being able to select grouped elements. A solution for that
is being worked on.
2019-07-17 21:39:35 -06:00
dbcce31ad3 Outliner: Show active improvements
Prevent the show active operator from scrolling beneath the
allowed scrolling range. This removes jumpy redraws after the
operator executes.

The horizontal centering is difficult, because the elements
outside the view of the outliner do not have the xend properly set
and the max width of the outliner is not properly calculated.
This means it is not possible to center the x position while
keeping the view in range of scrolling.

This could be resolved by drawing the outliner after setting the y
position, but that is not an ideal solution.
2019-07-17 18:49:18 -06:00
e664a324f1 Merge branch 'master' into soc-2019-outliner 2019-07-17 10:21:52 -06:00
9d28b8ae3f Outliner: Prevent scroll page from leaving view bounds
The page up/down operator to scroll the tree could go past the
bounds of the tree leading to jumpy redraws. This prevents the
operator to go outside the bounds of the area.
2019-07-16 22:35:28 -06:00
b4118991e7 Merge branch 'master' into soc-2019-outliner 2019-07-16 13:07:49 -06:00
e4c17ee9d1 Outliner: Redraw on scene camera change
This appears to be a redraw on any change in the scene..
wonder if there is a better way.
2019-07-15 19:42:01 -06:00
dda15a3e69 Outliner: Fix crash on duplicating scene
The function to determine if a collection was hidden was missing
a check to see if the layer collection was not null.
2019-07-15 19:41:06 -06:00
e63b87fb4d Outliner: Set active camera on camera data activate
Allow setting the active scene camera on camera data activate.

Not sure if all the depsgraph and event notifier calls are needed.
Tested removing some and it still worked.
2019-07-15 19:39:39 -06:00
93c4e1e369 Merge branch 'master' into soc-2019-outliner 2019-07-15 13:34:48 -06:00
5bb9fce0cd Collections: Update active collection after visibility restriction
When changing viewport visiblity or restriction change the active
collection. This replicates the behavior of excluding the active
collection, which sets the first non-excluded parent as active.

This required a function to recursively check parents for the
visiblility restrictions.
2019-07-15 13:29:42 -06:00
5962ff5da4 Merge branch 'master' into soc-2019-outliner 2019-07-13 16:49:23 -06:00
185e8183fa Outliner: Support multiple selected objects for parent clear
Clear parents for all selected objects on drag and drop
2019-07-13 16:48:09 -06:00
f8ca71e66a Outliner: Always do object parenting 2019-07-13 16:08:52 -06:00
d75d2860fd Outliner: Support multiple objects for parenting
Now parents multiple objects in the outliner on drag and drop.
This only works for setting an object as the parent, not for
armatures, lattices, etc. Will be improved on.
2019-07-11 22:45:53 -06:00
de5589f0ff Revert "Keymap: Simplify outliner select keymap"
This reverts most of commit 210600e7f6.
2019-07-11 22:44:26 -06:00
aa6c8f609c Outliner: Disable synced selection in certain modes
Certain display modes don't make sense, or don't work well for
selection syncing. This disables syncing in Blender Libraries,
Data API, and Orphans view.
2019-07-11 17:13:05 -06:00
210600e7f6 Keymap: Simplify outliner select keymap
Changed extend default and simplified the keymap
2019-07-11 16:16:16 -06:00
a78b73ac6f Outliner: Remove warnings
Left a few unused variables from removing old code
2019-07-11 16:15:24 -06:00
d2ea9f7bed Outliner: Improve walk select
Now that walk select doesn't start from active, some selection
operators and syncing needed to set the walk element. So after
some select operators, set the walk element alongside the active
element
2019-07-11 15:40:45 -06:00
b73fc56dfa Outliner: Cleanup sync code
Removed some commented code
2019-07-11 15:27:58 -06:00
e0bd7e67c1 Outliner: prevent bone selection when sync select disabled
More refinements to the synced selection code
2019-07-11 13:46:23 -06:00
137397836a Merge branch 'master' into soc-2019-outliner 2019-07-11 11:58:52 -06:00
c90bc0175c Outliner: Fix setting of active element from the outliner
The active element was being synced, which incorrectly failed
when clicking on object data and other non-base elements in the
outliner. Now it leaves activation to operators in the outliner
rather than syncing to avoid code duplication.
2019-07-11 11:56:42 -06:00
a284ca9d39 Outliner: Rewrite walk select
Rather than basing walk select on active flags, use a new TSE_WALK
flag to navigate. Also cleaned up and simplified code.
2019-07-10 14:30:02 -06:00
fd917935d1 Outliner: Utils made outliner_find_active more general
Rather than only searching for active, now search for element with
matching flag.
2019-07-10 11:50:07 -06:00
f04988e357 Merge branch 'master' into soc-2019-outliner 2019-07-10 10:22:32 -06:00
ddcb635ceb Merge branch 'master' into soc-2019-outliner 2019-07-09 18:42:46 -06:00
8e25a19a05 Outliner: Fix setting active when in edit mode
Fixes some small issues with setting active elements
2019-07-09 18:40:53 -06:00
c40ec17fd3 Outliner: Support selecting other objects when in edit/pose modes
When selecting in the outliner, rather than activating other
elements when in edit or pose mode, just select. This is useful
for selecting other objects while in edit/pose modes for adding
parents, hooks, etc.
2019-07-08 22:45:02 -06:00
63076a7d7f Outliner: Move active element code
Moves code for setting active element to activate function
rather than select function as this makes more sense
2019-07-08 22:10:57 -06:00
92f2d8b86b Merge branch 'master' into soc-2019-outliner 2019-07-08 10:44:03 -06:00
6c3564bff9 Outliner: Activate elements on walk select
Rather than just setting flags, activate outliner elements
to support toggling modes. This still needs some work while in
synced selection mode. Outside of synced selection it works
well
2019-07-06 22:23:44 -06:00
89c156d888 Merge branch 'master' into soc-2019-outliner 2019-07-06 14:56:41 -06:00
12283cdec8 Merge branch 'master' into soc-2019-outliner 2019-07-04 13:02:54 -06:00
7a78c32b58 Merge branch 'master' into soc-2019-outliner 2019-07-02 19:47:38 -06:00
064c4396c7 Outliner: Sync edit and pose bone selection state
Syncs selection to and from outliner for bones in both modes.

The code for pose bones is acceptable, but edit bones is quite
the mess. Something more intelligent needs to be thought of here.
2019-07-02 19:45:25 -06:00
1f37ee140b Synced Selection: Merge functions
Merged the sequence and base syncing functions together to
simplify and to make adding pose and edit bone syncing easier.
Also reduces the number of times the tree is looped over.
2019-07-02 11:15:16 -06:00
a9ee8d49b4 Outliner: Fix crash on range select when no active element exists
The old code incorrectly assumed that an active element always
existed. The fix is to set the cursor element to active when
no active element is found.
2019-07-02 10:48:32 -06:00
65c3f3e520 Outliner: Sync active sequences between outliner and sequencer
Active sequences are now synced on selection
2019-07-02 10:48:08 -06:00
f4948d2ce7 Outliner: Sync selection from outliner to sequencer
Outliner selection events now sync to the sequencer. Still need
to support active strips
2019-07-01 21:40:03 -06:00
c8aed23a1c Outliner: Draw correct scene icon
Was drawing incorrect icon for scene
2019-07-01 21:13:34 -06:00
9605cebdd2 Outliner: Sync selection from sequencer
Sequencer selection operators now sync to outliners. Still needs
to sync the other direction
2019-07-01 20:49:39 -06:00
35b5395f2a Outliner: Draw more sequencer icons
Not all of the sequencer icons had been added to the outliner.
Some are still drawing with editor/modifier colors so they will
need their own icons. Or some other code workaround.
2019-07-01 20:48:15 -06:00
5992e6c3e6 Merge branch 'master' into soc-2019-outliner 2019-07-01 20:35:31 -06:00
7b7772e180 Outliner: Fix range select sometimes leaving hidden elements selected
The range select opearator sometimes would leave other elements
selected when changing the active element. This is fixed by
clearing the selection each time the operator runs.
2019-07-01 11:05:56 -06:00
ff6c1027bd Merge branch 'master' into soc-2019-outliner 2019-06-29 22:44:18 -06:00
c91148c966 Outliner: Fix range select when active element is not selected
When the active element was not selected and range select
was used, it would become selected and the range select would
execute. A more intuitive behavior is to simply select the clicked
element.

Also optimized the outliner_is_element_visible utility function
2019-06-29 22:42:04 -06:00
3f52689590 Outliner: Move selection syncing functions to outliner_sync.c
This is just for organization. Also fixes a small error when
outliner select/deselect all still synced when selection syncing
was disabled.
2019-06-29 21:37:11 -06:00
cc3f7abbb0 Outliner: Move sync_select_dirty_flag to new file
Adds `outliner_sync.c` for the global rather than storing in Main.
2019-06-29 20:48:14 -06:00
d5ad3d6fc8 Outliner: Fix range selection on active element
Range select on active element was selecting down the entire tree
because there was no element to stop at. This is resolved by
not doing a range select when the cursor element and the active
element are the same.
2019-06-28 21:30:07 -06:00
6ee77a28a8 Outliner: Remove ctrl+click to rename
This conflicts with ctrl+click to extend selection, and is not
conventional. F2 and double click still function to rename
elements in the outliner.
2019-06-27 21:25:38 -06:00
7b440e5796 Merge branch 'master' into soc-2019-outliner 2019-06-27 21:23:57 -06:00
c68dff9ff7 Outliner: Add extend selection to walk select
Walk select now extends the selection when shift is pressed.
This implementation works well, though if there are existing
selections in the tree the behavior may not work as expected.
This could be improved on in the future if that is a problem.
2019-06-27 17:50:21 -06:00
e191fb3bda Outliner: Fix tree building not setting parents properly
When the scenes view tree was built, the parent for view layers
and objects were not set properly (either NULL or incorrect
parent), causing walk select to fail. Now the proper parents are
set.

Not sure if there was a reason why the wrong parent was set for
view layers before.
2019-06-27 15:42:14 -06:00
3de1bd9b38 Outliner: Fix walk selection wrapping and other issues
This prevents walk selection from wrapping around from the last
to the first tree element. Additionally, if the active tree
element is within a closed subtree, walk select will move the
active element to the first visible parent.

The operator code is also simplified and slightly optimized.
2019-06-27 15:39:46 -06:00
30e48c6c6a Outliner: Select active on walk select with no elements selected
Rather than actually walking the selection down from the active
element on walk select, the operator now only selects the active
element in the outliner.
2019-06-26 15:05:34 -06:00
e4ed727f43 Synced Selection: Sync active objects between outliner and view layer
This adds the syncing of active elements. When synced selection is off
and elements are selected, no activation or selection will occur.
When synced selection is enabled, active bases will be synced
in both directions between outliner and view layer.

Currently some issues still exist, like selecting a collection
will mark it active.
2019-06-26 14:53:12 -06:00
a4b99522f0 Merge branch 'master' into soc-2019-outliner 2019-06-26 14:13:37 -06:00
55e95e84d7 Outliner: Only draw active highlight when syncing selection
When synced selection is off, it makes no sense to draw
active highlights, especially because they may be out of
sync from view layer active highlights
2019-06-26 14:12:10 -06:00
89c0a27651 Merge branch 'master' into soc-2019-outliner 2019-06-25 19:50:07 -06:00
883399072f Synced Selection: Sync outliner selections to view layer
Outliner select operators now flush their selections to the
active view layer when synced selection is enabled.
2019-06-25 19:47:12 -06:00
99ceaf2ecc Synced Selection: Fix syncing not working
Removing some changes that were supposed to address extending
the selection, but they were preventing the replace selection
from behaving properly.
2019-06-25 07:32:54 -06:00
3906d6d500 Merge branch 'master' into soc-2019-outliner 2019-06-24 20:23:28 -06:00
20ae943bf4 Outliner: Redo synced selection dirty outliner implementation
The previous implementation assumed each selection type was identical
and synced each outliner with the 3D view. This had flaws because
hidden objects can be selected in the outliner, and it would be impossible
to know whether or not to keep them selected when syncing. To work around
that and other cases, this implementation does two things:

1. After any 3D view selection, sync selection flags with an outliner.
After syncing, a clean outliner is stored. Then the other outliners
are marked as dirty, to be synced from the clean outliner.

2. After an outliner select, that outliner is set as clean and the
other outliners are marked as dirty to be synced from.

More work is needed to support all outliner selection operations,
as well as properly supporting extending selections from the 3D
view. However, the underlying code for selection syncing should now
support the edge cases that the other implementation failed to
support.
2019-06-24 20:16:18 -06:00
801e973aa8 Outliner: Redraw 3D view after syncing selection
After deselect all in the outliner, the 3D view needs to be redrawn.
Also fix some syncing edge cases
2019-06-21 23:07:50 -06:00
64c5417017 Outliner: Enable synced selection by default
Mark outliners as dirty and enable synced selection for new
outliners. Also apply in versioning.
2019-06-21 15:44:23 -06:00
56314980ac Outliner: Add sync selection flag to main
The is_sync_select_dirty flag will be set after outliner and
3D viewport selection events to indicate a sync needs to occur.
2019-06-21 15:27:05 -06:00
6c82357176 Revert most of "Outliner: Refine synced selection"
This reverts the majority of commit
ad1ff2b601.

Rather than modifying ED_object_base_select to need the
view layer, use a global instead (for now)
2019-06-21 15:09:57 -06:00
fb439d5a87 Merge branch 'master' into soc-2019-outliner 2019-06-21 14:01:18 -06:00
a3688f0924 Merge branch 'master' into soc-2019-outliner 2019-06-18 16:40:10 -06:00
6864873372 Eyedropper: Support datablock picking in outliner
This adds support for picking datablocks from the outliner with the
eyedropper tool.

This requires changing the region the UI tooltip is drawn in by
tracking when the mouse moves to a different area on the screen.
By doing this the draw callback can be reset for each new area the
eyedropper enters.
2019-06-18 16:29:10 -06:00
0bc6448746 Outliner: Silence warning on visibility
Missing a break within a switch.
2019-06-18 10:58:22 -06:00
d1227026aa Merge branch 'soc-2019-outliner' of git.blender.org:blender into soc-2019-outliner 2019-06-17 22:54:49 -06:00
26b55532ba Outliner: Sync selection state on sync selection toggle
When turning on synced selection, sync the selection. Previously
this required clicking in the outliner or doing a 3D view selection
operation.
2019-06-17 22:53:50 -06:00
7979534279 Merge branch 'master' into soc-2019-outliner 2019-06-18 14:48:15 +10:00
33f237d04c Outliner: Don't adjust horizontal scroll on show active
The show active operator tried to scroll the outliner
horizontally to show the active object. On wide outliners this
caused a jittery redraw on mousemove. When the outliner
was more narrow, repeating the operation also caused
unexpected jittery redraws.
2019-06-17 22:35:18 -06:00
516cfd2250 Outliner: Fix TreeStore loading in textbutton edit mode
Fixes incorrectly added the TSE_ACTIVE flag field after TSE_SELECTED
because it logically made more sense there. Old files were loading
with each tree element in textbutton edit mode. This addresses that
and other issues with mismatches on TreeStoreElem flags.
2019-06-17 21:01:48 -06:00
93de8cf127 Outliner: Versioning for active element theme change
It doesn't have a version bump condition currently to always apply
the theme during the summer of code
2019-06-17 11:59:52 -06:00
2edb0f10c5 Merge branch 'master' into soc-2019-outliner 2019-06-17 10:43:13 -06:00
bb89b6788d Merge branch 'master' into soc-2019-outliner 2019-06-15 21:39:33 -06:00
e96f32a0ee Outliner: Add modifier keys to box select
Adds shift for add and ctrl for subtract, matching the 3D view
default keymap.
2019-06-15 21:37:55 -06:00
248060c884 Outliner: Show enable/disable button for constraints
This adds the restriction icon for constraints in the outliner so
they can be enabled/disabled similar to modifiers.

It also moves the icon definition to RNA from the UI template for
the constraints in the properties editor.
2019-06-14 23:03:27 -06:00
d2493bdd77 Outliner Visibility: Add Invisible filter
This adds an object invisible filter to the outliner to only show hidden
or disabled objects in the outliner. In large scenes, it is often
difficult to locate hidden objects in the outliner to show them again.
This invisible filter makes it easier.
2019-06-13 15:20:01 -06:00
1840fd4fa8 Merge branch 'master' into soc-2019-outliner 2019-06-13 14:16:29 -06:00
ad1ff2b601 Outliner: Refine synced selection
Any selection event that uses ED_object_base_select will now
mark the outliners as being dirty. When an outliner draws and is
dirty with synced selection enabled, it will sync its selection
state with the view layer.

More work still needs to be done. This may not be the best way
to implement it (selections from scripts won't be tracked). Also,
selection from the outliner isn't perfect.
2019-06-13 13:56:08 -06:00
213d0d6f70 Outliner: Add synced selection
This implementation is to see how syncing will be done, to be redone
later in a more general way. Right now each operator must explicitly
sync the selection.
2019-06-11 22:27:34 -06:00
8ee6fd8866 Outliner: Add dirty flag
This dirty flag is to indicate whether an outliner needs to sync
its selection state with the active view layer before redrawing
2019-06-11 22:13:05 -06:00
e680755ad7 Outliner: Remove negative from sync selection
Removing because it was behaving strangely. I might not entirely
understand what `negative_sdna` does
2019-06-11 21:47:40 -06:00
cae3c781e7 Outliner: Add sync selection property
Adds a toggle to each outliner for synced selection
2019-06-08 13:05:30 -06:00
0be0559fd1 Merge branch 'master' into soc-2019-outliner 2019-06-08 10:09:25 -06:00
c042f82b89 Outliner: Redraw on constraint reordering
Rather than restricting which constraint actions redraw the outliner,
all will (similar to modifiers). This will redraw on constraint
reorder
2019-06-08 09:04:55 -06:00
f5ccf5f035 Outliner: Draw constraint icons
Draws constraint icons in the outliner for bones and objects. The
only icon that has an issue is the Action constraint icon, because
it doesn't have a specific constraint icon, so it is drawn white
instead of blue.

At first I tried to replicate the code for modifier icons, then
I found a solution using `te->directdata` that worked for both
objects and bones. It works well enough, not sure if that simpler
solution should be used for modifiers too.
2019-06-08 08:26:19 -06:00
59955efb07 Fix: Use correct icon for armature deform constraint
Use constraint icon rather than modifier icon for consistency
2019-06-07 22:26:33 -06:00
886670fb63 Outliner: Fix walk select error on open leaf elements
In the outliner, leaf elements like light or material data do not
show a disclosure triangle. However, they can still be toggled
with a click or the openclose operator. This led to the walk select
attempting to walk down another level in the tree.

This could be fixed in the toggle open/close functions as well, but
it seems to address it in walk select seemed simpler as this is
the only area affected.
2019-06-06 22:51:43 -06:00
5d7a7dd7a0 Outliner: Fix crash on modifier key click in empty space
I changed this line earlier, I think while implementing box selection.
Changing it back to what it was before I modified it solved the issue.
2019-06-06 22:40:34 -06:00
b5d22f77e7 Outliner: Cleanup range and box select
Cleanup properties, keymap, code styling, and descriptions
2019-06-06 22:25:05 -06:00
43dedae029 Outliner: Cleanup active element
After discussion with Campbell, I realized that some ways I was using
active elements did not fit with Blender's way of things. Like box select
making the root of the tree active if no active element existed. These
issues are fixed, in addition to using the already-present `active`
Theme struct member.
2019-06-06 21:56:20 -06:00
0f998b27fc Outliner: Fix opening scenes by default
Keeping `sce == scene` for files with many scenes and having too many
open becomes unmaneageable.
2019-06-06 21:44:08 -06:00
c68ffd3394 Merge branch 'master' into soc-2019-outliner 2019-06-06 21:04:11 -06:00
07f938be38 Outliner: Finish walk select
Adds walk in and out for walk select (left and right arrows)
If an element is closed, walk in will open the element. If
the element is open, left will close it. Otherwise left moves the
active element to the parent.
2019-06-04 23:14:45 -06:00
729c81d947 Merge branch 'master' into soc-2019-outliner 2019-06-04 23:14:31 -06:00
3627e5b8d3 Outliner: Fix memroy error in walk select
Didn't close an EnumPropertyItem with NULL
2019-06-03 09:35:06 -06:00
a3acc8296c Merge branch 'master' into soc-2019-outliner 2019-06-03 09:06:06 -06:00
33502f6d2b Merge branch 'master' into soc-2019-outliner 2019-06-01 22:43:23 -06:00
73392fc29b Outliner: Add walk select operator
Adds a walk select operator to the outliner. Currently only up
and down walk are supported, opening and closing and walking left
and right will be added later.
2019-06-01 22:41:35 -06:00
9f4d65e488 Outliner: Allow box select from any empty space
This allows click and drag box select from anywhere except for name
and icons of elements. Currently the restriction toggles are a valid
locaion to select from. Could remove if it becomes an issue
2019-06-01 17:48:13 -06:00
b1a88dab43 Outliner: Remove range select restrictions
Removes restrictions for range select requiring a visible active element.
Now if no active element is visible the shift+clicked element is set as active and selected.
This way no warnings need to be reported.

Also silenced some warnings
2019-05-31 22:24:22 -06:00
aeba4958e5 Outliner: Fix scene elements closed by default
I committed this earlier but accidentally committed the submodules alongside it.
2019-05-31 21:54:01 -06:00
c5ff3aecc3 Revert "Outliner: Open Scene list elements by default"
This reverts commit a3448a9eef.

I accidentally included the submodules in the commit. Won't happen again!
2019-05-31 21:09:25 -06:00
cac85a4ecb Merge branch 'master' into soc-2019-outliner 2019-05-31 17:53:53 -06:00
333aa010bb Merge branch 'master' into soc-2019-outliner 2019-05-30 22:57:51 -06:00
155cb8505c Outliner: Click and drag to box select
Allows tweak event for box selection from the left gutter of the outliner.
If the gutter is clicked, everything is deselected
2019-05-30 22:53:52 -06:00
94be4ea6cf Outliner: Add range select
Adds range select to outliner_activate.
Range select is based on the active element and the clicked element.
If no active element is visible, report an error
2019-05-29 22:57:35 -06:00
558679a19e Outliner: Utils function is element visible 2019-05-29 22:56:09 -06:00
cdbd48b310 Merge branch 'master' into soc-2019-outliner 2019-05-29 21:42:09 -06:00
593aa62bce Outliner: Add range select to keymap
Changes keymap for outliner.item_activate
ctrl: extend
shift: range
alt: recursive
ctrl+alt: recursive extend
2019-05-29 21:40:04 -06:00
fda3351c88 Outliner: Utils function to find active element
Searches tree and returns active TreeElement
2019-05-29 07:54:52 -06:00
6cc800d845 Merge branch 'master' into soc-2019-outliner 2019-05-28 20:52:49 -06:00
3bedf72319 Outliner: Active element
Initial implementation for active elements. Currently works for select and extend selection
2019-05-28 20:47:25 -06:00
b2a716e033 Outliner: Add active element theme color
Adds a themable color for the outliner's active elements in both light and default themes
2019-05-28 16:04:03 -06:00
4ccf9a5b75 Merge branch 'master' into soc-2019-outliner 2019-05-27 22:25:43 -06:00
ed299c0f9d Merge branch 'master' into soc-2019-outliner 2019-05-25 13:56:23 -06:00
a3448a9eef Outliner: Open Scene list elements by default
Ensures that Scenes in the outliner scene display mode start opened.
2019-05-25 13:44:40 -06:00
36 changed files with 2033 additions and 336 deletions

View File

@@ -748,7 +748,8 @@ const bTheme U_theme_default = {
.outline_width = 1,
.facedot_size = 4,
.match = RGBA(0x337f334c),
.selected_highlight = RGBA(0x314e784c),
.selected_highlight = RGBA(0x223a5bff),
.active = RGBA(0x3b5689ff),
.selected_object = RGBA(0xe96a00ff),
.active_object = RGBA(0xffaf29ff),
.edited_object = RGBA(0x00806266),

View File

@@ -974,6 +974,7 @@
<ThemeOutliner
match="#337f33"
selected_highlight="#7a8e99"
active="#92aab7"
selected_object="#ffddb3"
active_object="#ffffff"
edited_object="#0080624d"

View File

@@ -700,20 +700,37 @@ def km_outliner(params):
items.extend([
("outliner.highlight_update", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("outliner.item_rename", {"type": 'F2', "value": 'PRESS'}, None),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK'},
{"properties": [("extend", False), ("recursive", False), ("deselect_all", not params.legacy)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", True), ("recursive", False)]}),
{"properties": [("extend", False), ("deselect_all", not params.legacy)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
{"properties": [("extend", False), ("recursive", True)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True},
{"properties": [("extend", True), ("recursive", True)]}),
{"properties": [("extend", True), ("deselect_all", not params.legacy)]}),
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("extend", False), ("extend_range", True), ("deselect_all", not params.legacy)]}),
("outliner.select_box", {"type": 'B', "value": 'PRESS'}, None),
("outliner.item_openclose", {"type": 'RET', "value": 'PRESS'},
("outliner.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, {"properties": [("tweak", True)]}),
("outliner.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True},
{"properties": [("tweak", True), ("mode", "ADD")]}),
("outliner.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "ctrl": True},
{"properties": [("tweak", True), ("mode", "SUB")]}),
("outliner.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'UP')]}),
("outliner.select_walk", {"type": 'UP_ARROW', "value": 'PRESS', "shift": True},
{"properties": [("direction", 'UP'), ("extend", True)]}),
("outliner.select_walk", {"type": 'DOWN_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'DOWN')]}),
("outliner.select_walk", {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True},
{"properties": [("direction", 'DOWN'), ("extend", True)]}),
("outliner.select_walk", {"type": 'LEFT_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'LEFT')]}),
("outliner.select_walk", {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True},
{"properties": [("direction", 'LEFT'), ("toggle_all", True)]}),
("outliner.select_walk", {"type": 'RIGHT_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'RIGHT')]}),
("outliner.select_walk", {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True},
{"properties": [("direction", 'RIGHT'), ("toggle_all", True)]}),
("outliner.item_openclose", {"type": 'LEFTMOUSE', "value": 'CLICK'},
{"properties": [("all", False)]}),
("outliner.item_openclose", {"type": 'RET', "value": 'PRESS', "shift": True},
("outliner.item_openclose", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
{"properties": [("all", True)]}),
("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
("outliner.item_openclose", {"type": 'EVT_TWEAK_L', "value": 'ANY'},
{"properties": [("all", False)]}),
("outliner.operation", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None),
("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True}, None),

View File

@@ -46,6 +46,10 @@ class OUTLINER_HT_header(Header):
layout.separator_spacer()
if display_mode == 'SEQUENCE':
row = layout.row(align=True)
row.prop(space, "use_sync_select", icon="UV_SYNC_SELECT", text="")
row = layout.row(align=True)
if display_mode in {'SCENES', 'VIEW_LAYER'}:
row.popover(
@@ -328,6 +332,10 @@ class OUTLINER_PT_filter(Panel):
col.prop(space, "use_sort_alpha")
layout.separator()
row = layout.row(align=True)
row.prop(space, "use_sync_select", text="Sync Selection")
layout.separator()
col = layout.column(align=True)
col.label(text="Search:")
col.prop(space, "use_filter_complete", text="Exact Match")

View File

@@ -493,6 +493,36 @@ static LayerCollection *collection_from_index(ListBase *lb, const int number, in
return NULL;
}
/**
* Determine if a collection is hidden, viewport visibility restricted, or excluded
*/
static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc)
{
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
return true;
}
/* Check visiblilty restriction flags */
if (lc->flag & LAYER_COLLECTION_HIDE || lc->collection->flag & COLLECTION_RESTRICT_VIEWPORT) {
return true;
}
else {
/* Restriction flags stay set, so we need to check parents */
CollectionParent *parent = lc->collection->parents.first;
if (parent) {
lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
return lc && layer_collection_hidden(view_layer, lc);
}
else {
return false;
}
}
return false;
}
/**
* Get the collection for a given index
*/
@@ -537,8 +567,9 @@ LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, Lay
lc = NULL;
}
if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
/* Don't activate excluded collections. */
/* Don't activate excluded or hidden collections to prevent creating objects in a hidden
* collection from the UI */
if (lc && layer_collection_hidden(view_layer, lc)) {
return BKE_layer_collection_activate_parent(view_layer, lc);
}
@@ -817,8 +848,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
/* Always set a valid active collection. */
LayerCollection *active = view_layer->active_collection;
if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
if (active && layer_collection_hidden(view_layer, active)) {
BKE_layer_collection_activate_parent(view_layer, active);
}
else if (active == NULL) {

View File

@@ -3644,6 +3644,19 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
arm->flag &= ~(ARM_FLAG_UNUSED_6);
}
/* Marks each outliner as dirty so a sync will occur as an outliner draws. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *space = sa->spacedata.first; space; space = space->next) {
if (space->spacetype == SPACE_OUTLINER) {
SpaceOutliner *soutliner = (SpaceOutliner *)space;
soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
soutliner->flag |= SO_SYNC_SELECT;
}
}
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 281, 1)) {

View File

@@ -141,6 +141,9 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
FROM_DEFAULT_V4_UCHAR(space_outliner.row_alternate);
}
FROM_DEFAULT_V4_UCHAR(space_outliner.selected_highlight);
FROM_DEFAULT_V4_UCHAR(space_outliner.active);
/**
* Include next version bump.
*/

View File

@@ -46,6 +46,7 @@
#include "ED_armature.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h"
@@ -356,6 +357,8 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
}
}
ED_outliner_select_sync_from_edit_bone_tag(C);
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
@@ -1027,6 +1030,8 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
ED_outliner_select_sync_from_edit_bone_tag(C);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
return OPERATOR_FINISHED;
@@ -1148,6 +1153,8 @@ static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
}
MEM_freeN(objects);
ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1178,6 +1185,8 @@ static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
}
MEM_freeN(objects);
ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1569,6 +1578,8 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op)
#undef STRUCT_SIZE_AND_OFFSET
ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1663,6 +1674,8 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
ED_outliner_select_sync_from_edit_bone_tag(C);
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
@@ -1748,6 +1761,8 @@ static int armature_select_mirror_exec(bContext *C, wmOperator *op)
arm->act_edbone = ebone_mirror_act;
}
ED_outliner_select_sync_from_edit_bone_tag(C);
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
@@ -1876,6 +1891,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
if (changed) {
arm->act_edbone = ebone_dst;
ED_outliner_select_sync_from_edit_bone_tag(C);
ED_armature_edit_sync_selection(arm->edbo);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);

View File

@@ -54,6 +54,7 @@
#include "ED_keyframing.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h"
@@ -449,6 +450,8 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
selectconnected_posebonechildren(base->object, curBone, extend);
}
ED_outliner_select_sync_from_pose_bone_tag(C);
ED_pose_bone_select_tag_update(base->object);
return OPERATOR_FINISHED;
@@ -514,6 +517,8 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
ED_outliner_select_sync_from_pose_bone_tag(C);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
return OPERATOR_FINISHED;
@@ -560,6 +565,8 @@ static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
ED_outliner_select_sync_from_pose_bone_tag(C);
ED_pose_bone_select_tag_update(ob);
return OPERATOR_FINISHED;
}
@@ -624,6 +631,8 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
return OPERATOR_CANCELLED;
}
ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -712,6 +721,8 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
ED_outliner_select_sync_from_pose_bone_tag(C);
ED_pose_bone_select_tag_update(ob);
return OPERATOR_FINISHED;
@@ -1061,6 +1072,8 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
/* report done status */
if (changed) {
ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
else {
@@ -1172,6 +1185,8 @@ static int pose_select_mirror_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}

View File

@@ -30,4 +30,17 @@ bool ED_outliner_collections_editor_poll(struct bContext *C);
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C);
void ED_outliner_select_sync_from_sequence_tag(struct bContext *C);
bool ED_outliner_select_sync_is_dirty(const struct bContext *C);
void ED_outliner_select_sync_from_outliner(struct bContext *C, struct SpaceOutliner *soops);
void ED_outliner_select_sync_flag_outliners(const struct bContext *C);
#endif /* __ED_OUTLINER_H__ */

View File

@@ -255,6 +255,7 @@ typedef enum ThemeColorID {
TH_MATCH, /* highlight color for search matches */
TH_SELECT_HIGHLIGHT, /* highlight color for selected outliner item */
TH_SELECT_ACTIVE, /* highlight color for active outliner item */
TH_SELECTED_OBJECT, /* selected object color for outliner */
TH_ACTIVE_OBJECT, /* active object color for outliner */
TH_EDITED_OBJECT, /* edited object color for outliner */

View File

@@ -51,6 +51,7 @@
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_outliner.h"
#include "interface_intern.h"
#include "interface_eyedropper_intern.h"
@@ -67,6 +68,7 @@ typedef struct DataDropper {
ID *init_id; /* for resetting on cancel */
ScrArea *cursor_area; /* Area under the cursor */
ARegionType *art;
void *draw_handle_pixel;
char name[200];
@@ -103,6 +105,7 @@ static int datadropper_init(bContext *C, wmOperator *op)
ddr->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO);
ddr->cursor_area = CTX_wm_area(C);
ddr->art = art;
ddr->draw_handle_pixel = ED_region_draw_cb_activate(
art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
@@ -141,7 +144,7 @@ static void datadropper_exit(bContext *C, wmOperator *op)
/* *** datadropper id helper functions *** */
/**
* \brief get the ID from the screen.
* \brief get the ID from the 3D view or outliner.
*/
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
{
@@ -155,7 +158,7 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
ddr->name[0] = '\0';
if (sa) {
if (sa->spacetype == SPACE_VIEW3D) {
if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
if (ar) {
const int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
@@ -167,7 +170,13 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
/* grr, always draw else we leave stale text */
ED_region_tag_redraw(ar);
base = ED_view3d_give_base_under_cursor(C, mval);
if (sa->spacetype == SPACE_VIEW3D) {
base = ED_view3d_give_base_under_cursor(C, mval);
}
else {
base = ED_outliner_give_base_under_cursor(C, mval);
}
if (base) {
Object *ob = base->object;
ID *id = NULL;
@@ -232,6 +241,36 @@ static void datadropper_cancel(bContext *C, wmOperator *op)
datadropper_exit(C, op);
}
/* To switch the draw callback when region under mouse event changes */
static void datadropper_set_draw_callback_region(bContext *C,
DataDropper *ddr,
const int mx,
const int my)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
if (sa) {
/* If spacetype changed */
if (sa->spacetype != ddr->cursor_area->spacetype) {
/* Remove old callback */
ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
/* Redraw old area */
ARegion *ar = BKE_area_find_region_type(ddr->cursor_area, RGN_TYPE_WINDOW);
ED_region_tag_redraw(ar);
/* Set draw callback in new region */
ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_WINDOW);
ddr->cursor_area = sa;
ddr->art = art;
ddr->draw_handle_pixel = ED_region_draw_cb_activate(
art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
}
}
}
/* main modal status check */
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -260,6 +299,10 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else if (event->type == MOUSEMOVE) {
ID *id = NULL;
/* Set the region for eyedropper cursor text drawing */
datadropper_set_draw_callback_region(C, ddr, event->x, event->y);
datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
}

View File

@@ -2523,7 +2523,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
/* enabled */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_HIDE_ON : ICON_HIDE_OFF);
uiItemR(row, &ptr, "mute", 0, "", 0);
UI_block_emboss_set(block, UI_EMBOSS);
uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);

View File

@@ -794,6 +794,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
cp = ts->selected_highlight;
break;
case TH_SELECT_ACTIVE:
cp = ts->active;
break;
case TH_SELECTED_OBJECT:
cp = ts->selected_object;
break;

View File

@@ -103,6 +103,7 @@
#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_physics.h"
#include "ED_render.h"
#include "ED_screen.h"
@@ -502,6 +503,8 @@ Object *ED_object_add_type(bContext *C,
/* TODO(sergey): Use proper flag for tagging here. */
DEG_id_tag_update(&scene->id, 0);
ED_outliner_select_sync_from_object_tag(C);
return ob;
}

View File

@@ -69,6 +69,7 @@
#include "ED_armature.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_keyframing.h"
@@ -436,6 +437,8 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -717,6 +720,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
if (changed) {
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -1100,6 +1104,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
if (changed) {
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -1150,6 +1155,8 @@ static int object_select_all_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
else if (any_visible == false) {
@@ -1218,6 +1225,8 @@ static int object_select_same_collection_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -1281,6 +1290,8 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -1369,6 +1380,9 @@ static int object_select_more_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
else {
@@ -1399,6 +1413,9 @@ static int object_select_less_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
else {
@@ -1448,6 +1465,8 @@ static int object_select_random_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}

View File

@@ -41,6 +41,7 @@ set(SRC
outliner_edit.c
outliner_ops.c
outliner_select.c
outliner_sync.c
outliner_tools.c
outliner_tree.c
outliner_utils.c

View File

@@ -326,38 +326,57 @@ static bool parent_drop_poll(bContext *C,
return false;
}
static int parent_drop_exec(bContext *C, wmOperator *op)
static void parent_drop_set_parents(
bContext *C, ReportList *reports, wmDragID *drag, Object *parent, short parent_type)
{
Object *par = NULL, *ob = NULL;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int partype = -1;
char parname[MAX_NAME], childname[MAX_NAME];
SpaceOutliner *soops = CTX_wm_space_outliner(C);
partype = RNA_enum_get(op->ptr, "type");
RNA_string_get(op->ptr, "parent", parname);
par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname);
RNA_string_get(op->ptr, "child", childname);
ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname);
TreeElement *te = outliner_find_id(soops, &soops->tree, &parent->id);
Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
if (ID_IS_LINKED(ob)) {
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
return OPERATOR_CANCELLED;
if (scene == NULL) {
/* currently outliner organized in a way, that if there's no parent scene
* element for object it means that all displayed objects belong to
* active scene and parenting them is allowed (sergey)
*/
scene = CTX_data_scene(C);
}
ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL);
bool parent_set = false;
bool linked_objects = false;
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
for (wmDragID *drag_id = drag; drag_id; drag_id = drag_id->next) {
if (GS(drag_id->id->name) == ID_OB) {
Object *object = (Object *)drag_id->id;
return OPERATOR_FINISHED;
/* Do nothing to linked data */
if (ID_IS_LINKED(object)) {
linked_objects = true;
continue;
}
if (ED_object_parent_set(
reports, C, scene, object, parent, parent_type, false, false, NULL)) {
parent_set = true;
}
}
}
if (linked_objects) {
BKE_report(reports, RPT_INFO, "Can't edit library linked object(s)");
}
if (parent_set) {
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
}
}
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te = outliner_drop_find(C, event);
TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
@@ -374,107 +393,15 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (ob == par) {
return OPERATOR_CANCELLED;
}
if (ID_IS_LINKED(ob)) {
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
if (event->custom != EVT_DATA_DRAGDROP) {
return OPERATOR_CANCELLED;
}
char childname[MAX_NAME];
char parname[MAX_NAME];
STRNCPY(childname, ob->id.name + 2);
STRNCPY(parname, par->id.name + 2);
RNA_string_set(op->ptr, "child", childname);
RNA_string_set(op->ptr, "parent", parname);
ListBase *lb = event->customdata;
wmDrag *drag = lb->first;
Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
if (scene == NULL) {
/* currently outlier organized in a way, that if there's no parent scene
* element for object it means that all displayed objects belong to
* active scene and parenting them is allowed (sergey)
*/
scene = CTX_data_scene(C);
}
if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) {
int partype = 0;
if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) {
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
}
}
else {
/* Menu creation */
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
PointerRNA ptr;
/* Cannot use uiItemEnumO()... have multiple properties to set. */
uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_OBJECT);
/* par becomes parent, make the associated menus */
if (par->type == OB_ARMATURE) {
uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE);
uiItemFullO_ptr(
layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
uiItemFullO_ptr(
layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
uiItemFullO_ptr(
layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_BONE);
}
else if (par->type == OB_CURVE) {
uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_CURVE);
uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_FOLLOW);
uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
}
else if (par->type == OB_LATTICE) {
uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
RNA_string_set(&ptr, "parent", parname);
RNA_string_set(&ptr, "child", childname);
RNA_enum_set(&ptr, "type", PAR_LATTICE);
}
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}
parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT);
return OPERATOR_FINISHED;
}
@@ -488,17 +415,11 @@ void OUTLINER_OT_parent_drop(wmOperatorType *ot)
/* api callbacks */
ot->invoke = parent_drop_invoke;
ot->exec = parent_drop_exec;
ot->poll = ED_operator_outliner_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
RNA_def_string(ot->srna, "child", "Object", MAX_NAME, "Child", "Child Object");
RNA_def_string(ot->srna, "parent", "Object", MAX_NAME, "Parent", "Parent Object");
RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
}
/* ******************** Parent Clear Operator *********************** */
@@ -549,13 +470,21 @@ static bool parent_clear_poll(bContext *C,
static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
if (ob == NULL) {
if (event->custom != EVT_DATA_DRAGDROP) {
return OPERATOR_CANCELLED;
}
ED_object_parent_clear(ob, 0);
ListBase *lb = event->customdata;
wmDrag *drag = lb->first;
for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
if (GS(drag_id->id->name) == ID_OB) {
Object *object = (Object *)drag_id->id;
ED_object_parent_clear(object, 0);
}
}
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -966,6 +895,12 @@ static int outliner_item_drag_drop_invoke(bContext *C,
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
float view_mval[2];
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP);
if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {

View File

@@ -31,6 +31,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_force_types.h"
#include "BLI_math.h"
@@ -60,6 +61,7 @@
#include "ED_armature.h"
#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
#include "WM_api.h"
@@ -848,6 +850,7 @@ typedef struct RestrictProperties {
PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only,
*layer_collection_hide_viewport;
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
} RestrictProperties;
/* We don't care about the value of the property
@@ -865,6 +868,7 @@ typedef struct RestrictPropertiesActive {
bool layer_collection_hide_viewport;
bool modifier_show_viewport;
bool modifier_show_render;
bool constraint_enable;
} RestrictPropertiesActive;
static void outliner_restrict_properties_enable_collection_set(
@@ -878,6 +882,7 @@ static void outliner_restrict_properties_enable_collection_set(
props_active->layer_collection_indirect_only = false;
props_active->object_hide_render = false;
props_active->modifier_show_render = false;
props_active->constraint_enable = false;
}
}
@@ -891,6 +896,7 @@ static void outliner_restrict_properties_enable_collection_set(
props_active->object_hide_viewport = false;
props_active->base_hide_viewport = false;
props_active->modifier_show_viewport = false;
props_active->constraint_enable = false;
}
}
@@ -995,6 +1001,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport");
props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render");
props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
props.initialized = true;
}
@@ -1181,6 +1189,35 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
}
}
else if (tselem->type == TSE_CONSTRAINT) {
bConstraint *con = (bConstraint *)te->directdata;
PointerRNA ptr;
RNA_pointer_create(tselem->id, &RNA_Constraint, con, &ptr);
if (soops->show_restrict_flags & SO_RESTRICT_HIDE) {
bt = uiDefIconButR_prop(block,
UI_BTYPE_ICON_TOGGLE,
0,
0,
(int)(ar->v2d.cur.xmax - restrict_offsets.hide),
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
&ptr,
props.constraint_enable,
-1,
0,
0,
-1,
-1,
NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
if (!props_active.constraint_enable) {
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
}
}
}
else if (tselem->type == TSE_MODIFIER) {
ModifierData *md = (ModifierData *)te->directdata;
@@ -1878,6 +1915,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_DEFGROUP_BASE:
data.icon = ICON_GROUP_VERTEX;
break;
case TSE_DEFGROUP:
data.icon = ICON_GROUP_VERTEX;
break;
case TSE_BONE:
case TSE_EBONE:
data.icon = ICON_BONE_DATA;
@@ -1885,6 +1925,100 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case TSE_CONSTRAINT_BASE:
data.icon = ICON_CONSTRAINT;
break;
case TSE_CONSTRAINT: {
bConstraint *con = te->directdata;
switch ((eBConstraint_Types)con->type) {
case CONSTRAINT_TYPE_CAMERASOLVER:
data.icon = ICON_CON_CAMERASOLVER;
break;
case CONSTRAINT_TYPE_FOLLOWTRACK:
data.icon = ICON_CON_FOLLOWTRACK;
break;
case CONSTRAINT_TYPE_OBJECTSOLVER:
data.icon = ICON_CON_OBJECTSOLVER;
break;
case CONSTRAINT_TYPE_LOCLIKE:
data.icon = ICON_CON_LOCLIKE;
break;
case CONSTRAINT_TYPE_ROTLIKE:
data.icon = ICON_CON_ROTLIKE;
break;
case CONSTRAINT_TYPE_SIZELIKE:
data.icon = ICON_CON_SIZELIKE;
break;
case CONSTRAINT_TYPE_TRANSLIKE:
data.icon = ICON_CON_TRANSLIKE;
break;
case CONSTRAINT_TYPE_DISTLIMIT:
data.icon = ICON_CON_DISTLIMIT;
break;
case CONSTRAINT_TYPE_LOCLIMIT:
data.icon = ICON_CON_LOCLIMIT;
break;
case CONSTRAINT_TYPE_ROTLIMIT:
data.icon = ICON_CON_ROTLIMIT;
break;
case CONSTRAINT_TYPE_SIZELIMIT:
data.icon = ICON_CON_SIZELIMIT;
break;
case CONSTRAINT_TYPE_SAMEVOL:
data.icon = ICON_CON_SAMEVOL;
break;
case CONSTRAINT_TYPE_TRANSFORM:
data.icon = ICON_CON_TRANSFORM;
break;
case CONSTRAINT_TYPE_TRANSFORM_CACHE:
data.icon = ICON_CON_TRANSFORM_CACHE;
break;
case CONSTRAINT_TYPE_CLAMPTO:
data.icon = ICON_CON_CLAMPTO;
break;
case CONSTRAINT_TYPE_DAMPTRACK:
data.icon = ICON_CON_TRACKTO;
break;
case CONSTRAINT_TYPE_KINEMATIC:
data.icon = ICON_CON_KINEMATIC;
break;
case CONSTRAINT_TYPE_LOCKTRACK:
data.icon = ICON_CON_LOCKTRACK;
break;
case CONSTRAINT_TYPE_SPLINEIK:
data.icon = ICON_CON_SPLINEIK;
break;
case CONSTRAINT_TYPE_STRETCHTO:
data.icon = ICON_CON_STRETCHTO;
break;
case CONSTRAINT_TYPE_TRACKTO:
data.icon = ICON_CON_TRACKTO;
break;
case CONSTRAINT_TYPE_ACTION:
data.icon = ICON_ACTION;
break;
case CONSTRAINT_TYPE_ARMATURE:
data.icon = ICON_CON_ARMATURE;
break;
case CONSTRAINT_TYPE_CHILDOF:
data.icon = ICON_CON_CHILDOF;
break;
case CONSTRAINT_TYPE_MINMAX:
data.icon = ICON_CON_FLOOR;
break;
case CONSTRAINT_TYPE_FOLLOWPATH:
data.icon = ICON_CON_FOLLOWPATH;
break;
case CONSTRAINT_TYPE_PIVOT:
data.icon = ICON_CON_PIVOT;
break;
case CONSTRAINT_TYPE_SHRINKWRAP:
data.icon = ICON_CON_SHRINKWRAP;
break;
default:
data.icon = ICON_DOT;
break;
}
break;
}
case TSE_MODIFIER_BASE:
data.icon = ICON_MODIFIER_DATA;
break;
@@ -2137,23 +2271,57 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.icon = ICON_GROUP_BONE;
break;
case TSE_SEQUENCE:
if (te->idcode == SEQ_TYPE_MOVIE) {
data.icon = ICON_SEQUENCE;
}
else if (te->idcode == SEQ_TYPE_META) {
data.icon = ICON_DOT;
}
else if (te->idcode == SEQ_TYPE_SCENE) {
data.icon = ICON_SCENE;
}
else if (te->idcode == SEQ_TYPE_SOUND_RAM) {
data.icon = ICON_SOUND;
}
else if (te->idcode == SEQ_TYPE_IMAGE) {
data.icon = ICON_IMAGE;
}
else {
data.icon = ICON_PARTICLES;
switch (te->idcode) {
case SEQ_TYPE_SCENE:
data.icon = ICON_SCENE_DATA;
break;
case SEQ_TYPE_MOVIECLIP:
data.icon = ICON_TRACKER;
break;
case SEQ_TYPE_MASK:
data.icon = ICON_MOD_MASK;
break;
case SEQ_TYPE_MOVIE:
data.icon = ICON_FILE_MOVIE;
break;
case SEQ_TYPE_SOUND_RAM:
data.icon = ICON_SOUND;
break;
case SEQ_TYPE_IMAGE:
data.icon = ICON_FILE_IMAGE;
break;
case SEQ_TYPE_COLOR:
case SEQ_TYPE_ADJUSTMENT:
data.icon = ICON_COLOR;
break;
case SEQ_TYPE_TEXT:
data.icon = ICON_FONT_DATA;
break;
case SEQ_TYPE_ADD:
case SEQ_TYPE_SUB:
case SEQ_TYPE_MUL:
case SEQ_TYPE_OVERDROP:
case SEQ_TYPE_ALPHAOVER:
case SEQ_TYPE_ALPHAUNDER:
case SEQ_TYPE_COLORMIX:
case SEQ_TYPE_MULTICAM:
case SEQ_TYPE_TRANSFORM:
case SEQ_TYPE_SPEED:
case SEQ_TYPE_GLOW:
case SEQ_TYPE_GAUSSIAN_BLUR:
data.icon = ICON_SHADERFX;
break;
case SEQ_TYPE_CROSS:
case SEQ_TYPE_GAMCROSS:
case SEQ_TYPE_WIPE:
data.icon = ICON_ARROW_LEFTRIGHT;
break;
case SEQ_TYPE_META:
data.icon = ICON_DOT;
break;
default:
data.icon = ICON_DOT;
break;
}
break;
case TSE_SEQ_STRIP:
@@ -2459,7 +2627,11 @@ static void tselem_draw_icon(uiBlock *block,
return;
}
/* Icon is covered by restrict buttons */
if (!is_clickable || x >= xmax) {
/* Reduce alpha to match icon buttons */
alpha *= 0.8f;
/* placement of icons, copied from interface_widgets.c */
float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
x += 2.0f * aspect;
@@ -2567,7 +2739,6 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
float ufac = UI_UNIT_X / 20.0f;
float icon_color[4], icon_border[4];
outliner_icon_background_colors(icon_color, icon_border);
icon_color[3] *= alpha_fac;
if (active == OL_DRAWSEL_ACTIVE) {
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color);
icon_border[3] = 0.3f;
@@ -2592,6 +2763,9 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
GPU_blend(true); /* Roundbox disables. */
}
if (tselem->flag & TSE_HIGHLIGHTED) {
alpha_fac += 0.5;
}
tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, alpha_fac, false);
te->xs = *offsx;
te->ys = ys;
@@ -2599,7 +2773,12 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
if (num_elements > 1) {
outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements);
te->flag |= TE_ICONROW_MERGED;
}
else {
te->flag |= TE_ICONROW;
}
(*offsx) += UI_UNIT_X;
}
@@ -2609,7 +2788,7 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
* We use a continuum of indices until we get to the object data-blocks
* and we then make room for the object types.
*/
static int tree_element_id_type_to_index(TreeElement *te)
int tree_element_id_type_to_index(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
@@ -2739,7 +2918,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
TreeElement *ten;
/* closed items may be displayed in row of parent, don't change their coordinate! */
if ((te->flag & TE_ICONROW) == 0) {
if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
/* store coord and continue, we need coordinates for elements outside view too */
te->xs = startx;
te->ys = starty;
@@ -3193,6 +3372,7 @@ static void outliner_draw_highlights_recursive(unsigned pos,
const SpaceOutliner *soops,
const ListBase *lb,
const float col_selection[4],
const float col_active[4],
const float col_highlight[4],
const float col_searchmatch[4],
int start_x,
@@ -3206,7 +3386,11 @@ static void outliner_draw_highlights_recursive(unsigned pos,
const int start_y = *io_start_y;
/* selection status */
if (tselem->flag & TSE_SELECTED) {
if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
immUniformColor4fv(col_active);
immRecti(pos, 0, start_y, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y);
}
else if (tselem->flag & TSE_SELECTED) {
immUniformColor4fv(col_selection);
immRecti(pos, 0, start_y, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y);
}
@@ -3260,6 +3444,7 @@ static void outliner_draw_highlights_recursive(unsigned pos,
soops,
&te->subtree,
col_selection,
col_active,
col_highlight,
col_searchmatch,
start_x + UI_UNIT_X,
@@ -3271,10 +3456,12 @@ static void outliner_draw_highlights_recursive(unsigned pos,
static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int startx, int *starty)
{
const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
float col_selection[4], col_searchmatch[4];
float col_selection[4], col_active[4], col_searchmatch[4];
UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection);
col_selection[3] = 1.0f; /* no alpha */
UI_GetThemeColor3fv(TH_SELECT_ACTIVE, col_active);
col_active[3] = 1.0f; /* no alpha */
UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
col_searchmatch[3] = 0.5f;
@@ -3282,8 +3469,16 @@ static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int star
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
outliner_draw_highlights_recursive(
pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, startx, starty);
outliner_draw_highlights_recursive(pos,
ar,
soops,
&soops->tree,
col_selection,
col_active,
col_highlight,
col_searchmatch,
startx,
starty);
immUnbindProgram();
GPU_blend(false);
}
@@ -3439,6 +3634,17 @@ void draw_outliner(const bContext *C)
outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
/* If global sync select is dirty, flag other outliners */
if (ED_outliner_select_sync_is_dirty(C)) {
ED_outliner_select_sync_flag_outliners(C);
}
/* Sync selection state from view layer */
if (!ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS) &&
soops->flag & SO_SYNC_SELECT) {
outliner_sync_selection(C, soops);
}
/* force display to pixel coords */
v2d->flag |= (V2D_PIXELOFS_X | V2D_PIXELOFS_Y);
/* set matrix for 2d-view controls */

View File

@@ -101,9 +101,15 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
ARegion *ar = CTX_wm_region(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my);
float view_mval[2];
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
if (hovered_te) {
hovered_te = outliner_find_item_at_x_in_row(soops, hovered_te, view_mval[0], NULL);
}
bool changed = false;
if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) {
@@ -134,59 +140,108 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
/* Toggle Open/Closed ------------------------------------------- */
static int do_outliner_item_openclose(
bContext *C, SpaceOutliner *soops, TreeElement *te, const bool all, const float mval[2])
/* Open or close a tree element, optionally toggling all children recursively */
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
{
TreeStoreElem *tselem = TREESTORE(te);
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
/* all below close/open? */
if (all) {
tselem->flag &= ~TSE_CLOSED;
outliner_flag_set(
&te->subtree, TSE_CLOSED, !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1));
}
else {
if (tselem->flag & TSE_CLOSED) {
tselem->flag &= ~TSE_CLOSED;
}
else {
tselem->flag |= TSE_CLOSED;
}
}
return 1;
if (open) {
tselem->flag &= ~TSE_CLOSED;
}
else {
tselem->flag |= TSE_CLOSED;
}
for (te = te->subtree.first; te; te = te->next) {
if (do_outliner_item_openclose(C, soops, te, all, mval)) {
return 1;
}
if (toggle_all) {
outliner_flag_set(&te->subtree, TSE_CLOSED, !open);
}
return 0;
}
/* event can enterkey, then it opens/closes */
static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event)
typedef struct OpenCloseData {
TreeStoreElem *prev_tselem;
bool open;
int x_location;
} OpenCloseData;
static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float fmval[2];
const bool all = RNA_boolean_get(op->ptr, "all");
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
float view_mval[2];
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
for (te = soops->tree.first; te; te = te->next) {
if (do_outliner_item_openclose(C, soops, te, all, fmval)) {
break;
if (event->type == MOUSEMOVE) {
TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
OpenCloseData *data = (OpenCloseData *)op->customdata;
/* Only openclose if mouse is not over the previously toggled element */
if (te && TREESTORE(te) != data->prev_tselem) {
/* Only toggle openclose on the same level as the first clicked element */
if (te->xs == data->x_location) {
outliner_item_openclose(te, data->open, false);
ED_region_tag_redraw(ar);
}
}
if (te) {
data->prev_tselem = TREESTORE(te);
}
else {
data->prev_tselem = NULL;
}
}
else if (event->val == KM_RELEASE) {
MEM_freeN(op->customdata);
ED_region_tag_redraw(ar);
return OPERATOR_FINISHED;
}
return OPERATOR_FINISHED;
return OPERATOR_RUNNING_MODAL;
}
static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
const bool toggle_all = RNA_boolean_get(op->ptr, "all");
float view_mval[2];
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
if (te && outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
TreeStoreElem *tselem = TREESTORE(te);
const bool open = (tselem->flag & TSE_CLOSED) ||
(toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)));
outliner_item_openclose(te, open, toggle_all);
ED_region_tag_redraw(ar);
/* Only toggle once for single click toggling */
if (event->type == LEFTMOUSE) {
return OPERATOR_FINISHED;
}
/* Store last expanded tselem and x coordinate of disclosure triangle */
OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data");
toggle_data->prev_tselem = tselem;
toggle_data->open = open;
toggle_data->x_location = te->xs;
/* Store the first clicked on element */
op->customdata = toggle_data;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
void OUTLINER_OT_item_openclose(wmOperatorType *ot)
@@ -195,11 +250,12 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
ot->idname = "OUTLINER_OT_item_openclose";
ot->description = "Toggle whether item under cursor is enabled or closed";
ot->invoke = outliner_item_openclose;
ot->invoke = outliner_item_openclose_invoke;
ot->modal = outliner_item_openclose_modal;
ot->poll = ED_operator_outliner_active;
RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items");
RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
}
/* -------------------------------------------------------------------- */
@@ -330,10 +386,10 @@ void item_rename_cb(bContext *C,
do_item_rename(ar, te, tselem, reports);
}
static int do_outliner_item_rename(ReportList *reports,
ARegion *ar,
TreeElement *te,
const float mval[2])
static void do_outliner_item_rename(ReportList *reports,
ARegion *ar,
TreeElement *te,
const float mval[2])
{
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -341,17 +397,12 @@ static int do_outliner_item_rename(ReportList *reports,
/* click on name */
if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) {
do_item_rename(ar, te, tselem, reports);
return 1;
}
return 0;
}
for (te = te->subtree.first; te; te = te->next) {
if (do_outliner_item_rename(reports, ar, te, mval)) {
return 1;
}
do_outliner_item_rename(reports, ar, te, mval);
}
return 0;
}
static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
@@ -360,25 +411,34 @@ static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *even
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float fmval[2];
bool changed = false;
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Rename active element if key pressed, otherwise rename element at cursor coordinates */
if (event->val == KM_PRESS) {
TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
for (te = soops->tree.first; te; te = te->next) {
if (do_outliner_item_rename(op->reports, ar, te, fmval)) {
changed = true;
break;
if (active_element) {
do_item_rename(ar, active_element, TREESTORE(active_element), op->reports);
}
else {
BKE_report(op->reports, RPT_WARNING, "No active item to rename");
}
}
else {
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
for (te = soops->tree.first; te; te = te->next) {
do_outliner_item_rename(op->reports, ar, te, fmval);
}
}
return changed ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
return OPERATOR_FINISHED;
}
void OUTLINER_OT_item_rename(wmOperatorType *ot)
{
ot->name = "Rename";
ot->idname = "OUTLINER_OT_item_rename";
ot->description = "Rename item under cursor";
ot->description = "Rename the active element";
ot->invoke = outliner_item_rename;
@@ -1103,6 +1163,10 @@ static int outliner_select_all_exec(bContext *C, wmOperator *op)
break;
}
if (soops->flag & SO_SYNC_SELECT) {
ED_outliner_select_sync_from_outliner(C, soops);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw_no_rebuild(ar);
@@ -1179,20 +1243,17 @@ static int outliner_open_back(TreeElement *te)
return retval;
}
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
/* Return element representing the active base or bone in the outliner, or NULL if none exists */
static TreeElement *outliner_show_active_get_element(bContext *C,
SpaceOutliner *so,
ViewLayer *view_layer)
{
SpaceOutliner *so = CTX_wm_space_outliner(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
TreeElement *te;
int xdelta, ytop;
Object *obact = OBACT(view_layer);
if (!obact) {
return OPERATOR_CANCELLED;
return NULL;
}
te = outliner_find_id(so, &so->tree, &obact->id);
@@ -1215,25 +1276,50 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
}
}
if (te) {
/* open up tree to active object/bone */
return te;
}
static void outliner_show_active(SpaceOutliner *so, ARegion *ar, TreeElement *te, ID *id)
{
/* open up tree to active object/bone */
if (TREESTORE(te)->id == id) {
if (outliner_open_back(te)) {
outliner_set_coordinates(ar, so);
}
return;
}
/* make te->ys center of view */
ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2;
if (ytop > 0) {
ytop = 0;
for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
outliner_show_active(so, ar, ten, id);
}
}
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceOutliner *so = CTX_wm_space_outliner(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
TreeElement *active_element = outliner_show_active_get_element(C, so, view_layer);
if (active_element) {
ID *id = TREESTORE(active_element)->id;
/* Expand all elements in the outliner with matching ID */
for (TreeElement *te = so->tree.first; te; te = te->next) {
outliner_show_active(so, ar, te, id);
}
v2d->cur.ymax = (float)ytop;
v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
/* Center view on first element found */
int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
int ytop = (active_element->ys + (size_y / 2));
int delta_y = ytop - v2d->cur.ymax;
/* make te->xs ==> te->xend center of view */
xdelta = (int)(te->xs - v2d->cur.xmin);
v2d->cur.xmin += xdelta;
v2d->cur.xmax += xdelta;
outliner_scroll_view(ar, delta_y);
}
else {
return OPERATOR_CANCELLED;
}
ED_region_tag_redraw_no_rebuild(ar);
@@ -1259,18 +1345,15 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
int dy = BLI_rcti_size_y(&ar->v2d.mask);
int up = 0;
int size_y = BLI_rcti_size_y(&ar->v2d.mask) + 1;
if (RNA_boolean_get(op->ptr, "up")) {
up = 1;
bool up = RNA_boolean_get(op->ptr, "up");
if (!up) {
size_y = -size_y;
}
if (up == 0) {
dy = -dy;
}
ar->v2d.cur.ymin += dy;
ar->v2d.cur.ymax += dy;
outliner_scroll_view(ar, size_y);
ED_region_tag_redraw_no_rebuild(ar);

View File

@@ -50,6 +50,14 @@ typedef enum TreeElementInsertType {
TE_INSERT_INTO,
} TreeElementInsertType;
/* Use generic walk select after D4771 is committed */
typedef enum WalkSelectDirection {
OUTLINER_SELECT_WALK_UP,
OUTLINER_SELECT_WALK_DOWN,
OUTLINER_SELECT_WALK_LEFT,
OUTLINER_SELECT_WALK_RIGHT,
} WalkSelectDirection;
typedef enum TreeTraversalAction {
/* Continue traversal regularly, don't skip children. */
TRAVERSE_CONTINUE = 0,
@@ -131,6 +139,9 @@ enum {
TE_DISABLED = (1 << 4),
TE_DRAGGING = (1 << 5),
TE_CHILD_NOT_IN_COLLECTION = (1 << 6),
/* Child elements of the same type in the iconrow are drawn merged as one icon.
* TE_ICONROW_MERGED is set for an element that is part of these merged child icons. */
TE_ICONROW_MERGED = (1 << 7),
};
/* button events */
@@ -223,6 +234,8 @@ void outliner_collection_isolate_flag(struct Scene *scene,
const char *propname,
const bool value);
int tree_element_id_type_to_index(TreeElement *te);
/* outliner_select.c -------------------------------------------- */
eOLDrawState tree_element_type_active(struct bContext *C,
struct Scene *scene,
@@ -253,6 +266,10 @@ void outliner_object_mode_toggle(struct bContext *C,
ViewLayer *view_layer,
Base *base);
void outliner_element_activate(struct SpaceOutliner *soops, struct TreeStoreElem *tselem);
bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_cb)(struct bContext *C,
struct ReportList *,
@@ -337,6 +354,8 @@ void item_object_mode_exit_cb(struct bContext *C,
void outliner_set_coordinates(struct ARegion *ar, struct SpaceOutliner *soops);
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all);
/* outliner_dragdrop.c */
void outliner_dropboxes(void);
@@ -364,6 +383,7 @@ void OUTLINER_OT_show_active(struct wmOperatorType *ot);
void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot);
void OUTLINER_OT_select_box(struct wmOperatorType *ot);
void OUTLINER_OT_select_walk(struct wmOperatorType *ot);
void OUTLINER_OT_select_all(struct wmOperatorType *ot);
void OUTLINER_OT_expanded_toggle(struct wmOperatorType *ot);
@@ -380,6 +400,10 @@ void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
/* outliner_tools.c ---------------------------------------------- */
void merged_element_search_menu_invoke(struct bContext *C,
TreeElement *parent_te,
TreeElement *activate_te);
void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
@@ -439,7 +463,8 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
float view_co_y);
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops,
const TreeElement *parent_te,
float view_co_x);
float view_co_x,
bool *multiple_objects);
TreeElement *outliner_find_tse(struct SpaceOutliner *soops, const TreeStoreElem *tse);
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
TreeElement *outliner_find_parent_element(ListBase *lb,
@@ -456,5 +481,12 @@ bool outliner_tree_traverse(const SpaceOutliner *soops,
TreeTraversalFunc func,
void *customdata);
float outliner_restrict_columns_width(const struct SpaceOutliner *soops);
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
bool outliner_is_element_visible(const TreeElement *te);
void outliner_scroll_view(struct ARegion *ar, int delta_y);
/* outliner_sync.c ---------------------------------------------- */
void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *soops);
#endif /* __OUTLINER_INTERN_H__ */

View File

@@ -50,6 +50,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_highlight_update);
WM_operatortype_append(OUTLINER_OT_item_activate);
WM_operatortype_append(OUTLINER_OT_select_box);
WM_operatortype_append(OUTLINER_OT_select_walk);
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
WM_operatortype_append(OUTLINER_OT_item_drag_drop);

View File

@@ -51,14 +51,16 @@
#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_sequencer.h"
#include "ED_undo.h"
#include "ED_gpencil.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -251,9 +253,7 @@ static eOLDrawState active_viewlayer(bContext *C,
}
/**
* Select object tree:
* CTRL+LMB: Select/Deselect object and all children.
* CTRL+SHIFT+LMB: Add/Remove object and all children.
* Select object tree
*/
static void do_outliner_object_select_recursive(ViewLayer *view_layer,
Object *ob_parent,
@@ -450,9 +450,9 @@ static eOLDrawState tree_element_active_material(bContext *C,
return OL_DRAWSEL_NONE;
}
static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
static eOLDrawState tree_element_active_camera(bContext *C,
Scene *scene,
ViewLayer *UNUSED(sl),
ViewLayer *UNUSED(view_layer),
SpaceOutliner *soops,
TreeElement *te,
const eOLSetState set)
@@ -460,10 +460,21 @@ static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
if (set != OL_SETSEL_NONE) {
scene->camera = ob;
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = bmain->wm.first;
WM_windows_scene_data_sync(&wm->windows, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL);
return OL_DRAWSEL_NONE;
}
return scene->camera == ob;
else {
return scene->camera == ob;
}
}
static eOLDrawState tree_element_active_world(bContext *C,
@@ -1083,6 +1094,13 @@ eOLDrawState tree_element_type_active(bContext *C,
/* ================================================ */
/* Activate a tree store element and set the walk navigation start element */
void outliner_element_activate(SpaceOutliner *soops, TreeStoreElem *tselem)
{
outliner_flag_set(&soops->tree, TSE_ACTIVE | TSE_ACTIVE_WALK, false);
tselem->flag |= TSE_ACTIVE | TSE_ACTIVE_WALK;
}
/**
* Action when clicking to activate an item (typically under the mouse cursor),
* but don't do any cursor intersection checks.
@@ -1114,7 +1132,8 @@ static void do_outliner_item_activate_tree_element(bContext *C,
else if (tselem->type == TSE_POSE_BASE) {
/* Support pose mode toggle, keeping the active object as is. */
}
else {
else if (soops->flag & SO_SYNC_SELECT) {
/* Only activate when synced selection is enabled */
tree_element_set_active_object(C,
scene,
view_layer,
@@ -1125,6 +1144,9 @@ static void do_outliner_item_activate_tree_element(bContext *C,
recursive && tselem->type == 0);
}
/* Mark as active in the outliner */
outliner_element_activate(soops, tselem);
if (tselem->type == 0) { // the lib blocks
/* editmode? */
if (te->idcode == ID_SCE) {
@@ -1189,7 +1211,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false);
}
}
else {
else if (soops->flag & SO_SYNC_SELECT) {
tree_element_type_active(C,
scene,
view_layer,
@@ -1211,7 +1233,8 @@ void outliner_item_select(SpaceOutliner *soops,
const bool toggle)
{
TreeStoreElem *tselem = TREESTORE(te);
const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED);
const short new_flag = (toggle && (tselem->flag & TSE_ACTIVE)) ? (tselem->flag ^ TSE_SELECTED) :
(tselem->flag | TSE_SELECTED);
if (extend == false) {
outliner_flag_set(&soops->tree, TSE_SELECTED, false);
@@ -1219,24 +1242,66 @@ void outliner_item_select(SpaceOutliner *soops,
tselem->flag = new_flag;
}
static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children)
static void do_outliner_range_select_recursive(ListBase *lb,
TreeElement *active,
TreeElement *cursor,
bool *selecting)
{
TreeStoreElem *tselem = TREESTORE(te);
if (toggle_children) {
tselem->flag &= ~TSE_CLOSED;
for (TreeElement *te = lb->first; te; te = te->next) {
if (*selecting) {
TREESTORE(te)->flag |= TSE_SELECTED;
}
const bool all_opened = !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1);
outliner_flag_set(&te->subtree, TSE_CLOSED, all_opened);
}
else {
tselem->flag ^= TSE_CLOSED;
/* Set state for selection */
if (te == active || te == cursor) {
*selecting = !*selecting;
}
if (*selecting) {
TREESTORE(te)->flag |= TSE_SELECTED;
}
/* Don't look inside closed elements */
if (!(TREESTORE(te)->flag & TSE_CLOSED)) {
do_outliner_range_select_recursive(&te->subtree, active, cursor, selecting);
}
}
}
static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
/* Select a range of items between cursor and active element */
static void do_outliner_range_select(bContext *C, SpaceOutliner *soops, TreeElement *cursor)
{
return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) &&
(view_co_x < te->xs + UI_UNIT_X);
TreeElement *active = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
outliner_flag_set(&soops->tree, TSE_ACTIVE_WALK, false);
if (!active) {
outliner_item_select(soops, cursor, false, false);
outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false);
return;
}
TreeStoreElem *tselem = TREESTORE(active);
const bool active_selected = (tselem->flag & TSE_SELECTED);
outliner_flag_set(&soops->tree, TSE_SELECTED | TSE_ACTIVE_WALK, false);
/* Select active if under cursor */
if (active == cursor) {
TREESTORE(cursor)->flag |= TSE_SELECTED;
return;
}
/* If active is not selected, just select the element under the cursor */
if (!active_selected || !outliner_is_element_visible(active)) {
outliner_item_select(soops, cursor, false, false);
outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false);
return;
}
outliner_flag_set(&soops->tree, TSE_SELECTED, false);
bool selecting = false;
do_outliner_range_select_recursive(&soops->tree, active, cursor, &selecting);
}
static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
@@ -1247,7 +1312,7 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
}
/**
* A version of #outliner_item_do_acticate_from_cursor that takes the tree element directly.
* A version of #outliner_item_do_activate_from_cursor that takes the tree element directly.
* and doesn't depend on the pointer position.
*
* This allows us to simulate clicking on an item without dealing with the mouse cursor.
@@ -1271,10 +1336,11 @@ void outliner_item_do_activate_from_tree_element(
static int outliner_item_do_activate_from_cursor(bContext *C,
const int mval[2],
const bool extend,
const bool recursive,
const bool use_range,
const bool deselect_all)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float view_mval[2];
@@ -1292,21 +1358,36 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
changed = true;
}
}
else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
outliner_item_toggle_closed(te, extend);
changed = true;
rebuild_tree = true;
/* Don't allow toggle on scene collection */
else if ((TREESTORE(te)->type != TSE_VIEW_COLLECTION_BASE) &&
outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
else {
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
/* the row may also contain children, if one is hovered we want this instead of current te */
TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]);
/* The row may also contain children, if one is hovered we want this instead of current te */
bool merged_elements = false;
TreeElement *activate_te = outliner_find_item_at_x_in_row(
soops, te, view_mval[0], &merged_elements);
/* If the selected icon was an aggregate of multiple elements, run the search popup */
if (merged_elements) {
merged_element_search_menu_invoke(C, te, activate_te);
return OPERATOR_CANCELLED;
}
TreeStoreElem *activate_tselem = TREESTORE(activate_te);
outliner_item_select(soops, activate_te, extend, extend);
do_outliner_item_activate_tree_element(
C, scene, view_layer, soops, activate_te, activate_tselem, extend, recursive);
if (use_range) {
do_outliner_range_select(C, soops, activate_te);
}
else {
outliner_item_select(soops, activate_te, extend, extend);
do_outliner_item_activate_tree_element(
C, scene, view_layer, soops, activate_te, activate_tselem, extend, false);
}
changed = true;
}
@@ -1318,6 +1399,10 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
ED_region_tag_redraw_no_rebuild(ar);
}
ED_undo_push(C, "Outliner selection change");
if (soops->flag & SO_SYNC_SELECT) {
ED_outliner_select_sync_from_outliner(C, soops);
}
}
return OPERATOR_FINISHED;
@@ -1327,9 +1412,9 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool recursive = RNA_boolean_get(op->ptr, "recursive");
const bool use_range = RNA_boolean_get(op->ptr, "extend_range");
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
return outliner_item_do_activate_from_cursor(C, event->mval, extend, recursive, deselect_all);
return outliner_item_do_activate_from_cursor(C, event->mval, extend, use_range, deselect_all);
}
void OUTLINER_OT_item_activate(wmOperatorType *ot)
@@ -1344,7 +1429,10 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
PropertyRNA *prop;
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection for activation");
RNA_def_boolean(ot->srna, "recursive", false, "Recursive", "Select Objects and their children");
prop = RNA_def_boolean(
ot->srna, "extend_range", false, "Extend Range", "Select a range from active element");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"deselect_all",
false,
@@ -1402,9 +1490,44 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(ar);
if (soops->flag & SO_SYNC_SELECT) {
ED_outliner_select_sync_from_outliner(C, soops);
}
return OPERATOR_FINISHED;
}
/* Find if x coordinate is over an icon or name */
static bool outliner_item_is_co_over_name_icons(TreeElement *te, float view_co_x)
{
/* Special case: count area left of Scene Collection as empty space */
bool outside_left = (TREESTORE(te)->type == TSE_VIEW_COLLECTION_BASE) ?
(view_co_x > te->xs + UI_UNIT_X) :
(view_co_x > te->xs);
return outside_left && (view_co_x < te->xend);
}
static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceOutliner *soops = CTX_wm_space_outliner(C);
ARegion *ar = CTX_wm_region(C);
float view_mval[2];
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
/* Find element clicked on */
TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
/* Pass through if click is over name or icons, or not tweak event */
if (te && tweak && outliner_item_is_co_over_name_icons(te, view_mval[0])) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
return WM_gesture_box_invoke(C, op, event);
}
void OUTLINER_OT_select_box(wmOperatorType *ot)
{
/* identifiers */
@@ -1413,7 +1536,7 @@ void OUTLINER_OT_select_box(wmOperatorType *ot)
ot->description = "Use box selection to select tree elements";
/* api callbacks */
ot->invoke = WM_gesture_box_invoke;
ot->invoke = outliner_box_select_invoke;
ot->exec = outliner_box_select_exec;
ot->modal = WM_gesture_box_modal;
ot->cancel = WM_gesture_box_cancel;
@@ -1424,8 +1547,240 @@ void OUTLINER_OT_select_box(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop;
prop = RNA_def_boolean(
ot->srna, "tweak", false, "Tweak", "Tweak gesture from empty space for box selection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
WM_operator_properties_gesture_box(ot);
WM_operator_properties_select_operation_simple(ot);
}
/* ****************************************************** */
/* **************** Walk Select Tool ****************** */
/* Given a tree element return the rightmost child that is visible in the outliner */
static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *soops, TreeElement *te)
{
while (te->subtree.last) {
if (TSELEM_OPEN(TREESTORE(te), soops)) {
te = te->subtree.last;
}
else {
break;
}
}
return te;
}
/* Find previous visible element in the tree */
static TreeElement *outliner_find_previous_element(SpaceOutliner *soops, TreeElement *walk_element)
{
if (walk_element->prev) {
walk_element = outliner_find_rightmost_visible_child(soops, walk_element->prev);
}
else if (walk_element->parent) {
/* Use parent if at beginning of list */
walk_element = walk_element->parent;
}
return walk_element;
}
/* Recursively search up the tree until a successor to a given element is found */
static TreeElement *outliner_element_find_successor_in_parents(TreeElement *te)
{
TreeElement *successor = te;
while (successor->parent) {
if (successor->parent->next) {
te = successor->parent->next;
break;
}
else {
successor = successor->parent;
}
}
return te;
}
/* Find next visible element in the tree */
static TreeElement *outliner_find_next_element(SpaceOutliner *soops, TreeElement *walk_element)
{
TreeStoreElem *tselem = TREESTORE(walk_element);
if (TSELEM_OPEN(tselem, soops) && walk_element->subtree.first) {
walk_element = walk_element->subtree.first;
}
else if (walk_element->next) {
walk_element = walk_element->next;
}
else {
walk_element = outliner_element_find_successor_in_parents(walk_element);
}
return walk_element;
}
static TreeElement *do_outliner_select_walk(SpaceOutliner *soops,
TreeElement *walk_element,
const int direction,
const bool extend,
const bool toggle_all)
{
TreeStoreElem *tselem = TREESTORE(walk_element);
if (!extend) {
outliner_flag_set(&soops->tree, TSE_SELECTED, false);
}
tselem->flag &= ~TSE_ACTIVE_WALK;
switch (direction) {
case OUTLINER_SELECT_WALK_UP:
walk_element = outliner_find_previous_element(soops, walk_element);
break;
case OUTLINER_SELECT_WALK_DOWN:
walk_element = outliner_find_next_element(soops, walk_element);
break;
case OUTLINER_SELECT_WALK_LEFT:
outliner_item_openclose(walk_element, false, toggle_all);
break;
case OUTLINER_SELECT_WALK_RIGHT:
outliner_item_openclose(walk_element, true, toggle_all);
break;
}
TreeStoreElem *tselem_new = TREESTORE(walk_element);
/* If new element is already selected, deselect the previous element */
if (extend) {
tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) :
(tselem->flag | TSE_SELECTED);
}
tselem_new->flag |= TSE_SELECTED | TSE_ACTIVE_WALK;
return walk_element;
}
/* Find walk select element, or set it if it does not exist.
* Changed is set to true if walk element is found, false if it was set */
static TreeElement *find_walk_select_start_element(SpaceOutliner *soops, bool *changed)
{
TreeElement *walk_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE_WALK);
*changed = false;
/* If no walk element exists, start from active */
if (!walk_element) {
TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
/* If no active element exists, use the first element in the tree */
if (!active_element) {
walk_element = soops->tree.first;
}
else {
walk_element = active_element;
}
*changed = true;
}
/* If walk element is not visible, set that element's first visible parent as walk element */
if (!outliner_is_element_visible(walk_element)) {
TREESTORE(walk_element)->flag &= ~TSE_ACTIVE_WALK;
while (!outliner_is_element_visible(walk_element)) {
walk_element = walk_element->parent;
}
*changed = true;
}
return walk_element;
}
/* Scroll the outliner when the walk element reaches the top or bottom boundary */
static void outliner_walk_scroll(ARegion *ar, TreeElement *te)
{
/* Account for the header height */
int y_max = ar->v2d.cur.ymax - UI_UNIT_Y;
int y_min = ar->v2d.cur.ymin;
/* Scroll if walked position is beyond the border */
if (te->ys > y_max) {
outliner_scroll_view(ar, te->ys - y_max);
}
else if (te->ys < y_min) {
outliner_scroll_view(ar, -(y_min - te->ys));
}
}
static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
SpaceOutliner *soops = CTX_wm_space_outliner(C);
ARegion *ar = CTX_wm_region(C);
const short direction = RNA_enum_get(op->ptr, "direction");
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all");
bool changed;
TreeElement *walk_element = find_walk_select_start_element(soops, &changed);
/* If finding the starting walk select element did not move the element, proceed to walk */
if (!changed) {
walk_element = do_outliner_select_walk(soops, walk_element, direction, extend, toggle_all);
}
else {
TREESTORE(walk_element)->flag |= TSE_SELECTED | TSE_ACTIVE_WALK;
}
/* Scroll outliner to focus on walk element */
outliner_walk_scroll(ar, walk_element);
if (soops->flag & SO_SYNC_SELECT) {
ED_outliner_select_sync_from_outliner(C, soops);
}
ED_region_tag_redraw(ar);
return OPERATOR_FINISHED;
}
void OUTLINER_OT_select_walk(wmOperatorType *ot)
{
static const EnumPropertyItem direction_items[] = {
{OUTLINER_SELECT_WALK_UP, "UP", 0, "Up", ""},
{OUTLINER_SELECT_WALK_DOWN, "DOWN", 0, "Down", ""},
{OUTLINER_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""},
{OUTLINER_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Walk Select";
ot->idname = "OUTLINER_OT_select_walk";
ot->description = "Use walk navigation to select tree elements";
/* api callbacks */
ot->invoke = outliner_walk_select_invoke;
ot->poll = ED_operator_outliner_active;
/* properties */
PropertyRNA *prop;
prop = RNA_def_enum(ot->srna,
"direction",
direction_items,
0,
"Walk Direction",
"Select element in this direction");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection on walk");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "toggle_all", false, "Toggle All", "Toggle open/close hierarchy");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ****************************************************** */

View File

@@ -0,0 +1,548 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2004 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup spoutliner
*/
#include <stdio.h>
#include "DNA_armature_types.h"
#include "DNA_layer_types.h"
#include "DNA_outliner_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "DEG_depsgraph.h"
#include "ED_armature.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "WM_api.h"
#include "WM_types.h"
#include "outliner_intern.h"
/* Functions for tagging outliner selection syncing is dirty from operators */
void ED_outliner_select_sync_from_object_tag(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
}
void ED_outliner_select_sync_from_edit_bone_tag(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
}
void ED_outliner_select_sync_from_pose_bone_tag(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE;
}
void ED_outliner_select_sync_from_sequence_tag(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE;
}
bool ED_outliner_select_sync_is_dirty(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
return wm->outliner_sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL;
}
/* Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw */
void ED_outliner_select_sync_flag_outliners(const bContext *C)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOutliner *soutliner = (SpaceOutliner *)sl;
soutliner->sync_select_dirty |= wm->outliner_sync_select_dirty;
}
}
}
}
/* Clear global sync flag */
wm->outliner_sync_select_dirty = 0;
}
/**
* Outliner sync select dirty flags are not enough to determine which types to sync,
* outliner display mode also needs to be considered. This stores the types of data
* to sync to increase code clarity.
*/
typedef struct SyncSelectTypes {
bool object;
bool edit_bone;
bool pose_bone;
bool sequence;
} SyncSelectTypes;
/**
* Set which types of data to sync when syncing selection from the outliner based on object
* interaction mode and outliner display mode
*/
static void outliner_sync_select_from_outliner_set_types(bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT);
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE);
sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE);
sync_types->sequence = sequence_view;
}
/**
* Current dirty flags and outliner display mode determine which type of syncing should occur.
* This is to ensure sync flag data is not lost on sync in the wrong display mode.
*/
static void outliner_sync_select_to_outliner_set_types(const bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_OBJECT);
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE);
sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE);
sync_types->sequence = sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE);
}
/**
* Stores items selected from a sync from the outliner. Prevents syncing the selection
* state of the last instance of an object linked in multiple collections.
*/
typedef struct SelectedItems {
GSet *objects;
GSet *edit_bones;
GSet *pose_bones;
} SelectedItems;
static void selected_items_init(SelectedItems *selected_items)
{
selected_items->objects = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
selected_items->edit_bones = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
selected_items->pose_bones = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
}
static void selected_items_free(SelectedItems *selected_items)
{
BLI_gset_free(selected_items->objects, NULL);
BLI_gset_free(selected_items->edit_bones, NULL);
BLI_gset_free(selected_items->pose_bones, NULL);
}
/* Check if an instance of this object been selected by the sync */
static bool is_object_selected(GSet *selected_objects, Base *base)
{
return BLI_gset_haskey(selected_objects, base);
}
/* Check if an instance of this edit bone been selected by the sync */
static bool is_edit_bone_selected(GSet *selected_ebones, EditBone *ebone)
{
return BLI_gset_haskey(selected_ebones, ebone);
}
/* Check if an instance of this pose bone been selected by the sync */
static bool is_pose_bone_selected(GSet *selected_pbones, bPoseChannel *pchan)
{
return BLI_gset_haskey(selected_pbones, pchan);
}
/* Add element's data to selected item set */
static void add_selected_item(GSet *selected, void *data)
{
BLI_gset_add(selected, data);
}
static void outliner_select_sync_to_object(ViewLayer *view_layer,
TreeElement *te,
TreeStoreElem *tselem,
GSet *selected_objects)
{
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(view_layer, ob);
if (base && (base->flag & BASE_SELECTABLE)) {
if (tselem->flag & TSE_SELECTED) {
ED_object_base_select(base, BA_SELECT);
add_selected_item(selected_objects, base);
}
else if (!is_object_selected(selected_objects, base)) {
ED_object_base_select(base, BA_DESELECT);
}
}
}
static void outliner_select_sync_to_edit_bone(ViewLayer *view_layer,
TreeElement *te,
TreeStoreElem *tselem,
GSet *selected_ebones)
{
bArmature *arm = (bArmature *)tselem->id;
EditBone *ebone = (EditBone *)te->directdata;
short bone_flag = ebone->flag;
if (EBONE_SELECTABLE(arm, ebone)) {
if (tselem->flag & TSE_SELECTED) {
ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
add_selected_item(selected_ebones, ebone);
}
else if (!is_edit_bone_selected(selected_ebones, ebone)) {
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
}
/* Tag if selection changed */
if (bone_flag != ebone->flag) {
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, obedit);
}
}
static void outliner_select_sync_to_pose_bone(TreeElement *te,
TreeStoreElem *tselem,
GSet *selected_pbones)
{
Object *ob = (Object *)tselem->id;
bArmature *arm = ob->data;
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
short bone_flag = pchan->bone->flag;
if (PBONE_SELECTABLE(arm, pchan->bone)) {
if (tselem->flag & TSE_SELECTED) {
pchan->bone->flag |= BONE_SELECTED;
add_selected_item(selected_pbones, pchan);
}
else if (!is_pose_bone_selected(selected_pbones, pchan)) {
pchan->bone->flag &= ~BONE_SELECTED;
}
}
/* Tag if selection changed */
if (bone_flag != pchan->bone->flag) {
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ob);
}
}
static void outliner_select_sync_to_sequence(Scene *scene, TreeStoreElem *tselem)
{
Sequence *seq = (Sequence *)tselem->id;
if (tselem->flag & TSE_ACTIVE) {
BKE_sequencer_active_set(scene, seq);
}
if (tselem->flag & TSE_SELECTED) {
seq->flag |= SELECT;
}
else {
seq->flag &= ~SELECT;
}
}
/** Sync select and active flags from outliner to active view layer, bones, and sequencer. */
static void outliner_sync_selection_from_outliner(Scene *scene,
ViewLayer *view_layer,
ListBase *tree,
const SyncSelectTypes *sync_types,
SelectedItems *selected_items)
{
for (TreeElement *te = tree->first; te; te = te->next) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
if (sync_types->object) {
outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects);
}
}
else if (tselem->type == TSE_EBONE) {
if (sync_types->edit_bone) {
outliner_select_sync_to_edit_bone(view_layer, te, tselem, selected_items->edit_bones);
}
}
else if (tselem->type == TSE_POSE_CHANNEL) {
if (sync_types->pose_bone) {
outliner_select_sync_to_pose_bone(te, tselem, selected_items->pose_bones);
}
}
else if (tselem->type == TSE_SEQUENCE) {
if (sync_types->sequence) {
outliner_select_sync_to_sequence(scene, tselem);
}
}
outliner_sync_selection_from_outliner(
scene, view_layer, &te->subtree, sync_types, selected_items);
}
}
/* Set clean outliner and mark other outliners for syncing */
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops)
{
/* Don't sync in certain outliner display modes */
if (ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) {
return;
}
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SyncSelectTypes sync_types;
outliner_sync_select_from_outliner_set_types(C, soops, &sync_types);
/* To store elements that have been selected to prevent linked object sync errors */
SelectedItems selected_items;
selected_items_init(&selected_items);
outliner_sync_selection_from_outliner(
scene, view_layer, &soops->tree, &sync_types, &selected_items);
selected_items_free(&selected_items);
/* Tag for updates */
if (sync_types.object) {
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
if (sync_types.sequence) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
}
/* Clear outliner sync select dirty flag to prevent a sync to the outliner on draw */
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_ALL;
}
static void outliner_select_sync_from_object(ViewLayer *view_layer,
SpaceOutliner *soops,
Object *obact,
TreeElement *te,
TreeStoreElem *tselem)
{
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
BKE_view_layer_base_find(view_layer, ob);
const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
if (base && (ob == obact)) {
outliner_element_activate(soops, tselem);
}
if (is_selected) {
tselem->flag |= TSE_SELECTED;
}
else {
tselem->flag &= ~TSE_SELECTED;
}
}
static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops,
EditBone *ebone_active,
TreeElement *te,
TreeStoreElem *tselem)
{
EditBone *ebone = (EditBone *)te->directdata;
if (ebone == ebone_active) {
outliner_element_activate(soops, tselem);
}
if (ebone->flag & BONE_SELECTED) {
tselem->flag |= TSE_SELECTED;
}
else {
tselem->flag &= ~TSE_SELECTED;
}
}
static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops,
bPoseChannel *pchan_active,
TreeElement *te,
TreeStoreElem *tselem)
{
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
if (pchan == pchan_active) {
outliner_element_activate(soops, tselem);
}
if (bone->flag & BONE_SELECTED) {
tselem->flag |= TSE_SELECTED;
}
else {
tselem->flag &= ~TSE_SELECTED;
}
}
static void outliner_select_sync_from_sequence(SpaceOutliner *soops,
Sequence *sequence_active,
TreeStoreElem *tselem)
{
Sequence *seq = (Sequence *)tselem->id;
if (seq == sequence_active) {
outliner_element_activate(soops, tselem);
}
if (seq->flag & SELECT) {
tselem->flag |= TSE_SELECTED;
}
else {
tselem->flag &= ~TSE_SELECTED;
}
}
/**
* Contains active object, bones, and sequence for syncing to prevent getting active data
* repeatedly throughout syncing to the outliner.
*/
typedef struct SyncSelectActiveData {
Object *object;
EditBone *edit_bone;
bPoseChannel *pose_channel;
Sequence *sequence;
} SyncSelectActiveData;
/** Sync select and active flags from active view layer, bones, and sequences to the outliner. */
static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
SpaceOutliner *soops,
ListBase *tree,
SyncSelectActiveData *active_data,
const SyncSelectTypes *sync_types)
{
for (TreeElement *te = tree->first; te; te = te->next) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
if (sync_types->object) {
outliner_select_sync_from_object(view_layer, soops, active_data->object, te, tselem);
}
}
else if (tselem->type == TSE_EBONE) {
if (sync_types->edit_bone) {
outliner_select_sync_from_edit_bone(soops, active_data->edit_bone, te, tselem);
}
}
else if (tselem->type == TSE_POSE_CHANNEL) {
if (sync_types->pose_bone) {
outliner_select_sync_from_pose_bone(soops, active_data->pose_channel, te, tselem);
}
}
else if (tselem->type == TSE_SEQUENCE) {
if (sync_types->sequence) {
outliner_select_sync_from_sequence(soops, active_data->sequence, tselem);
}
}
else {
tselem->flag &= ~TSE_SELECTED;
}
/* Sync subtree elements */
outliner_sync_selection_to_outliner(view_layer, soops, &te->subtree, active_data, sync_types);
}
}
/* Get active data from context */
static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData *active_data)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
active_data->object = OBACT(view_layer);
active_data->edit_bone = CTX_data_active_bone(C);
active_data->pose_channel = CTX_data_active_pose_bone(C);
active_data->sequence = BKE_sequencer_active_get(scene);
}
/* If outliner is dirty sync selection from view layer and sequwncer */
void outliner_sync_selection(const bContext *C, SpaceOutliner *soops)
{
if (soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL) {
ViewLayer *view_layer = CTX_data_view_layer(C);
/* Set which types of data to sync from sync dirty flag and outliner display mode */
SyncSelectTypes sync_types;
outliner_sync_select_to_outliner_set_types(C, soops, &sync_types);
/* Store active object, bones, and sequence */
SyncSelectActiveData active_data;
get_sync_select_active_data(C, &active_data);
outliner_sync_selection_to_outliner(
view_layer, soops, &soops->tree, &active_data, &sync_types);
/* Keep any unsynced data in the dirty flag */
if (sync_types.object) {
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
}
if (sync_types.edit_bone) {
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
}
if (sync_types.pose_bone) {
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE;
}
if (sync_types.sequence) {
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE;
}
}
}

View File

@@ -63,6 +63,7 @@
#include "ED_armature.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
@@ -478,6 +479,127 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
}
/* ******************************************** */
/* Stores the parent and a child element of a merged iconrow icon for
* the merged select popup menu. The subtree of the parent is searched and
* the child is needed to only show elements of the same type in the popup. */
typedef struct MergedSearchData {
TreeElement *parent_element;
TreeElement *select_element;
} MergedSearchData;
static void merged_element_search_cb_recursive(
const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
{
char name[64];
int iconid;
for (TreeElement *te = tree->first; te; te = te->next) {
TreeStoreElem *tselem = TREESTORE(te);
if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
if (BLI_strcasestr(te->name, str)) {
BLI_strncpy(name, te->name, 64);
iconid = tree_element_get_icon(tselem, te).icon;
/* Don't allow duplicate named items */
if (UI_search_items_find_index(items, name) == -1) {
if (!UI_search_item_add(items, name, te, iconid)) {
break;
}
}
}
}
merged_element_search_cb_recursive(&te->subtree, tselem_type, type, str, items);
}
}
/* Get a list of elements that match the search string */
static void merged_element_search_cb(const bContext *UNUSED(C),
void *data,
const char *str,
uiSearchItems *items)
{
MergedSearchData *search_data = (MergedSearchData *)data;
TreeElement *parent = search_data->parent_element;
TreeElement *te = search_data->select_element;
int type = tree_element_id_type_to_index(te);
merged_element_search_cb_recursive(&parent->subtree, TREESTORE(te)->type, type, str, items);
}
/* Activate an element from the merged element search menu */
static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1), void *element)
{
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te = (TreeElement *)element;
outliner_item_select(soops, te, false, false);
outliner_item_do_activate_from_tree_element(C, te, te->store_elem, false, false);
if (soops->flag & SO_SYNC_SELECT) {
ED_outliner_select_sync_from_outliner(C, soops);
}
}
/** Merged element search menu
* Created on activation of a merged or aggregated iconrow icon.
*/
static uiBlock *merged_element_search_menu(bContext *C, ARegion *ar, void *data)
{
static char search[64] = "";
uiBlock *block;
uiBut *but;
/* Clear search on each menu creation */
*search = '\0';
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
short menu_width = 10 * UI_UNIT_X;
but = uiDefSearchBut(
block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
UI_but_func_search_set(
but, NULL, merged_element_search_cb, data, false, merged_element_search_call_cb, NULL);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* Fake button to hold space for search items */
uiDefBut(block,
UI_BTYPE_LABEL,
0,
"",
10,
10 - UI_searchbox_size_y(),
menu_width,
UI_searchbox_size_y(),
NULL,
0,
0,
0,
0,
NULL);
/* Center the menu on the cursor */
UI_block_bounds_set_popup(block, 6, (const int[2]){-(menu_width / 2), 0});
return block;
}
void merged_element_search_menu_invoke(bContext *C,
TreeElement *parent_te,
TreeElement *activate_te)
{
MergedSearchData *select_data = MEM_callocN(sizeof(MergedSearchData), "merge_search_data");
select_data->parent_element = parent_te;
select_data->select_element = activate_te;
UI_popup_block_invoke(C, merged_element_search_menu, select_data, MEM_freeN);
}
static void object_select_cb(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),

View File

@@ -297,7 +297,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops,
ViewLayer *view_layer;
for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0);
TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, ten, TSE_R_LAYER, 0);
tenlay->name = view_layer->name;
tenlay->directdata = view_layer;
}
@@ -314,7 +314,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops,
ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0);
ten->name = IFACE_("Objects");
FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0);
outliner_add_element(soops, &ten->subtree, ob, ten, 0, 0);
}
FOREACH_SCENE_OBJECT_END;
outliner_make_object_parent_hierarchy(&ten->subtree);
@@ -2008,6 +2008,9 @@ static int outliner_exclude_filter_get(SpaceOutliner *soops)
case SO_FILTER_OB_VISIBLE:
exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
break;
case SO_FILTER_OB_INVISIBLE:
exclude_filter |= SO_FILTER_OB_STATE_INVISIBLE;
break;
case SO_FILTER_OB_SELECTED:
exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
break;
@@ -2086,6 +2089,11 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
return false;
}
}
else if (exclude_filter & SO_FILTER_OB_STATE_INVISIBLE) {
if ((base->flag & BASE_VISIBLE) != 0) {
return false;
}
}
else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
if ((base->flag & BASE_SELECTED) == 0) {
return false;
@@ -2339,7 +2347,8 @@ void outliner_build_tree(
te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
tselem = TREESTORE(te);
if (sce == scene && show_opened) {
/* New scene elements open by default */
if ((sce == scene && show_opened) || !tselem->used) {
tselem->flag &= ~TSE_CLOSED;
}

View File

@@ -24,11 +24,15 @@
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_context.h"
#include "BKE_outliner_treehash.h"
#include "BKE_layer.h"
#include "ED_armature.h"
#include "ED_outliner.h"
#include "UI_interface.h"
#include "UI_view2d.h"
@@ -62,6 +66,38 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
return NULL;
}
static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te,
float view_co_x,
bool *r_merged)
{
TreeElement *child_te = parent_te->subtree.first;
bool over_element = false;
while (child_te) {
over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
if ((child_te->flag & TE_ICONROW) && over_element) {
return child_te;
}
else if ((child_te->flag & TE_ICONROW_MERGED) && over_element) {
if (r_merged) {
*r_merged = true;
}
return child_te;
}
TreeElement *te = outliner_find_item_at_x_in_row_recursive(child_te, view_co_x, r_merged);
if (te != child_te) {
return te;
}
child_te = child_te->next;
}
/* return parent if no child is hovered */
return (TreeElement *)parent_te;
}
/**
* Collapsed items can show their children as click-able icons. This function tries to find
* such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
@@ -70,24 +106,14 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
*/
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops,
const TreeElement *parent_te,
float view_co_x)
float view_co_x,
bool *r_merged)
{
/* if parent_te is opened, it doesn't show childs in row */
/* if parent_te is opened, it doesn't show children in row */
if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) {
/* no recursion, items can only display their direct children in the row */
for (TreeElement *child_te = parent_te->subtree.first;
/* don't look further if co_x is smaller than child position*/
child_te && view_co_x >= child_te->xs;
child_te = child_te->next) {
if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) &&
(view_co_x < child_te->xend)) {
return child_te;
}
}
return outliner_find_item_at_x_in_row_recursive(parent_te, view_co_x, r_merged);
}
/* return parent if no child is hovered */
return (TreeElement *)parent_te;
}
@@ -300,3 +326,89 @@ float outliner_restrict_columns_width(const SpaceOutliner *soops)
}
return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH);
}
/* Find first tree element in tree with matching treestore flag */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
{
for (TreeElement *te = lb->first; te; te = te->next) {
if ((TREESTORE(te)->flag & flag) == flag) {
return te;
}
TreeElement *active_element = outliner_find_element_with_flag(&te->subtree, flag);
if (active_element) {
return active_element;
}
}
return NULL;
}
/* Find if element is visible in the outliner tree */
bool outliner_is_element_visible(const TreeElement *te)
{
TreeStoreElem *tselem;
while (te->parent) {
tselem = TREESTORE(te->parent);
if (tselem->flag & TSE_CLOSED) {
return false;
}
else {
te = te->parent;
}
}
return true;
}
/* Find if x coordinate is over element disclosure toggle */
bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
{
return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
}
/* Scroll view vertically while keeping within total bounds */
void outliner_scroll_view(ARegion *ar, int delta_y)
{
int y_min = MIN2(ar->v2d.cur.ymin, ar->v2d.tot.ymin);
ar->v2d.cur.ymax += delta_y;
ar->v2d.cur.ymin += delta_y;
/* Adjust view if delta placed view outside total area */
int offset;
if (ar->v2d.cur.ymax > -UI_UNIT_Y) {
offset = ar->v2d.cur.ymax;
ar->v2d.cur.ymax -= offset;
ar->v2d.cur.ymin -= offset;
}
else if (ar->v2d.cur.ymin < y_min) {
offset = y_min - ar->v2d.cur.ymin;
ar->v2d.cur.ymax += offset;
ar->v2d.cur.ymin += offset;
}
}
/* Get base of object under cursor. Used for eyedropper tool */
Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
{
ARegion *ar = CTX_wm_region(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
Base *base = NULL;
float view_mval[2];
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
if (te) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0) {
Object *ob = (Object *)tselem->id;
base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob);
}
}
return base;
}

View File

@@ -131,6 +131,9 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
break;
}
if (wmn->action & NA_EDITED) {
ED_region_tag_redraw(ar);
}
break;
case NC_OBJECT:
switch (wmn->data) {
@@ -145,13 +148,8 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
break;
case ND_CONSTRAINT:
switch (wmn->action) {
case NA_ADDED:
case NA_REMOVED:
case NA_RENAME:
ED_region_tag_redraw(ar);
break;
}
/* all constraint actions now, for reordering */
ED_region_tag_redraw(ar);
break;
case ND_MODIFIER:
/* all modifier actions now */
@@ -304,6 +302,8 @@ static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED(
soutliner->filter_id_type = ID_GR;
soutliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE;
soutliner->outlinevis = SO_VIEW_LAYER;
soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
soutliner->flag |= SO_SYNC_SELECT;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for outliner");
@@ -349,6 +349,9 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
soutlinern->treestore = NULL;
soutlinern->treehash = NULL;
soutlinern->flag |= (soutliner->flag & SO_SYNC_SELECT);
soutlinern->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL;
return (SpaceLink *)soutlinern;
}
@@ -415,7 +418,7 @@ void ED_spacetype_outliner(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
art->init = outliner_main_region_init;
art->draw = outliner_main_region_draw;
@@ -428,7 +431,7 @@ void ED_spacetype_outliner(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
art->init = outliner_header_region_init;
art->draw = outliner_header_region_draw;

View File

@@ -41,6 +41,7 @@
/* for menu/popup icons etc etc*/
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_select_utils.h"
@@ -49,6 +50,7 @@
/* own include */
#include "sequencer_intern.h"
static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2))
{
return NULL;
@@ -254,6 +256,8 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -293,6 +297,8 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
}
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -542,6 +548,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
/* allowing tweaks */
@@ -668,6 +676,8 @@ static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -699,6 +709,8 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -750,6 +762,8 @@ static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, cons
selected = select_more_less_seq__internal(scene, 1, 1);
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -784,6 +798,8 @@ static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
selected = select_more_less_seq__internal(scene, true, true);
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -832,6 +848,8 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
}
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -876,6 +894,8 @@ static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
select_active_side(
ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -934,6 +954,8 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
}
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
@@ -1311,6 +1333,7 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
}
if (changed) {
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
return OPERATOR_FINISHED;
}

View File

@@ -88,6 +88,7 @@
#include "ED_particle.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_sculpt.h"
@@ -1280,9 +1281,15 @@ static bool view3d_lasso_select(
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_pose_bone_tag(C);
}
}
else {
changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_object_tag(C);
}
}
}
else { /* Edit Mode */
@@ -1303,6 +1310,9 @@ static bool view3d_lasso_select(
break;
case OB_ARMATURE:
changed = do_lasso_select_armature(vc, mcords, moves, sel_op);
if (changed) {
ED_outliner_select_sync_from_edit_bone_tag(C);
}
break;
case OB_MBALL:
changed = do_lasso_select_meta(vc, mcords, moves, sel_op);
@@ -1488,6 +1498,9 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
else {
@@ -2350,6 +2363,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
if (!retval && deselect_all) {
retval = ED_armature_edit_deselect_all_visible_multi(C);
}
if (retval) {
ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
else if (obedit->type == OB_LATTICE) {
retval = ED_lattice_select_pick(C, location, extend, deselect, toggle);
@@ -2410,6 +2426,15 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
}
}
if (retval) {
if (obact && obact->mode & OB_MODE_POSE) {
ED_outliner_select_sync_from_pose_bone_tag(C);
}
else {
ED_outliner_select_sync_from_object_tag(C);
}
}
}
/* Pass-through allows tweaks
@@ -3230,6 +3255,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
if (changed) {
DEG_id_tag_update(&vc.obedit->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
ED_outliner_select_sync_from_edit_bone_tag(C);
}
break;
case OB_LATTICE:
@@ -3264,9 +3290,15 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
}
else if (vc.obact && vc.obact->mode & OB_MODE_POSE) {
changed_multi = do_pose_box_select(C, &vc, &rect, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_pose_bone_tag(C);
}
}
else { /* object mode with none active */
changed_multi = do_object_box_select(C, &vc, &rect, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_object_tag(C);
}
}
}
@@ -3890,7 +3922,8 @@ static bool mball_circle_select(ViewContext *vc,
/** Callbacks for circle selection in Editmode */
static bool obedit_circle_select(ViewContext *vc,
static bool obedit_circle_select(bContext *C,
ViewContext *vc,
wmGenericUserData *wm_userdata,
const eSelectOp sel_op,
const int mval[2],
@@ -3911,6 +3944,9 @@ static bool obedit_circle_select(ViewContext *vc,
break;
case OB_ARMATURE:
changed = armature_circle_select(vc, sel_op, mval, rad);
if (changed) {
ED_outliner_select_sync_from_edit_bone_tag(C);
}
break;
case OB_MBALL:
changed = mball_circle_select(vc, sel_op, mval, rad);
@@ -3999,7 +4035,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
obedit = vc.obedit;
if (obedit) {
obedit_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, (float)radius);
}
else if (BKE_paint_select_face_test(obact)) {
paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
@@ -4009,6 +4045,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
}
else if (obact->mode & OB_MODE_POSE) {
pose_circle_select(&vc, sel_op, mval, (float)radius);
ED_outliner_select_sync_from_pose_bone_tag(C);
}
else {
BLI_assert(0);
@@ -4029,6 +4066,8 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
if (object_circle_select(&vc, sel_op, mval, (float)radius)) {
DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
ED_outliner_select_sync_from_object_tag(C);
}
}

View File

@@ -60,6 +60,10 @@ enum {
TSE_DRAG_INTO = (1 << 6),
TSE_DRAG_BEFORE = (1 << 7),
TSE_DRAG_AFTER = (1 << 8),
/* Needed because outliner-only elements can be active */
TSE_ACTIVE = (1 << 9),
/* Needed because walk selection should not activate */
TSE_ACTIVE_WALK = (1 << 10),
TSE_DRAG_ANY = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER),
};

View File

@@ -244,7 +244,12 @@ typedef struct SpaceOutliner {
char search_string[64];
struct TreeStoreElem search_tse;
short flag, outlinevis, storeflag, search_flags;
short flag, outlinevis, storeflag;
char search_flags;
/** Selection syncing flag (#WM_OUTLINER_SYNC_SELECT_FROM_OBJECT and similar flags). */
char sync_select_dirty;
int filter;
char filter_state;
char show_restrict_flags;
@@ -263,6 +268,7 @@ typedef enum eSpaceOutliner_Flag {
SO_FLAG_UNUSED_1 = (1 << 2), /* cleared */
SO_HIDE_KEYINGSETINFO = (1 << 3),
SO_SKIP_SORT_ALPHA = (1 << 4),
SO_SYNC_SELECT = (1 << 5),
} eSpaceOutliner_Flag;
/* SpaceOutliner.filter */
@@ -281,13 +287,14 @@ typedef enum eSpaceOutliner_Filter {
SO_FILTER_NO_OB_CAMERA = (1 << 10),
SO_FILTER_NO_OB_OTHERS = (1 << 11),
SO_FILTER_UNUSED_12 = (1 << 12), /* cleared */
SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
SO_FILTER_OB_STATE_SELECTED = (1 << 14), /* Not set via DNA. */
SO_FILTER_OB_STATE_ACTIVE = (1 << 15), /* Not set via DNA. */
SO_FILTER_NO_COLLECTION = (1 << 16),
SO_FILTER_UNUSED_12 = (1 << 12), /* cleared */
SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
SO_FILTER_OB_STATE_INVISIBLE = (1 << 14), /* Not set via DNA. */
SO_FILTER_OB_STATE_SELECTED = (1 << 15), /* Not set via DNA. */
SO_FILTER_OB_STATE_ACTIVE = (1 << 16), /* Not set via DNA. */
SO_FILTER_NO_COLLECTION = (1 << 17),
SO_FILTER_ID_TYPE = (1 << 17),
SO_FILTER_ID_TYPE = (1 << 18),
} eSpaceOutliner_Filter;
#define SO_FILTER_OB_TYPE \
@@ -295,7 +302,8 @@ typedef enum eSpaceOutliner_Filter {
SO_FILTER_NO_OB_LAMP | SO_FILTER_NO_OB_CAMERA | SO_FILTER_NO_OB_OTHERS)
#define SO_FILTER_OB_STATE \
(SO_FILTER_OB_STATE_VISIBLE | SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE)
(SO_FILTER_OB_STATE_VISIBLE | SO_FILTER_OB_STATE_INVISIBLE | SO_FILTER_OB_STATE_SELECTED | \
SO_FILTER_OB_STATE_ACTIVE)
#define SO_FILTER_ANY \
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
@@ -305,8 +313,9 @@ typedef enum eSpaceOutliner_Filter {
typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_ALL = 0,
SO_FILTER_OB_VISIBLE = 1,
SO_FILTER_OB_SELECTED = 2,
SO_FILTER_OB_ACTIVE = 3,
SO_FILTER_OB_INVISIBLE = 2,
SO_FILTER_OB_SELECTED = 3,
SO_FILTER_OB_ACTIVE = 4,
} eSpaceOutliner_StateFilter;
/* SpaceOutliner.show_restrict_flags */

View File

@@ -131,12 +131,15 @@ typedef struct wmWindowManager {
ListBase windows;
/** Set on file read. */
int initialized;
short initialized;
/** Indicator whether data was saved. */
short file_saved;
/** Operator stack depth to avoid nested undo pushes. */
short op_undo_depth;
/** Set after selection to notify outliner to sync. Stores type of selection */
short outliner_sync_select_dirty;
/** Operator registry. */
ListBase operators;
@@ -186,6 +189,18 @@ enum {
WM_KEYCONFIG_IS_INITIALIZED = (1 << 1),
};
/* wmWindowManager.outliner_sync_select_dirty */
enum {
WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0),
WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1),
WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE = (1 << 2),
WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE = (1 << 3),
};
#define WM_OUTLINER_SYNC_SELECT_FROM_ALL \
(WM_OUTLINER_SYNC_SELECT_FROM_OBJECT | WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE | \
WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE | WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE)
#define WM_KEYCONFIG_STR_DEFAULT "blender"
/* IME is win32 only! */

View File

@@ -1009,7 +1009,7 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Armature Constraint", "Applies transformations done by the Armature modifier");
RNA_def_struct_sdna_from(srna, "bArmatureConstraint", "data");
RNA_def_struct_ui_icon(srna, ICON_MOD_ARMATURE);
RNA_def_struct_ui_icon(srna, ICON_CON_ARMATURE);
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
@@ -3026,6 +3026,7 @@ void RNA_def_constraint(BlenderRNA *brna)
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);

View File

@@ -2777,6 +2777,7 @@ static void rna_def_space_outliner(BlenderRNA *brna)
static const EnumPropertyItem filter_state_items[] = {
{SO_FILTER_OB_ALL, "ALL", 0, "All", "Show all objects in the view layer"},
{SO_FILTER_OB_VISIBLE, "VISIBLE", 0, "Visible", "Show visible objects"},
{SO_FILTER_OB_INVISIBLE, "INVISIBLE", 0, "Invisible", "Show invisible objects"},
{SO_FILTER_OB_SELECTED, "SELECTED", 0, "Selected", "Show selected objects"},
{SO_FILTER_OB_ACTIVE, "ACTIVE", 0, "Active", "Show only the active object"},
{0, NULL, 0, NULL, NULL},
@@ -2815,6 +2816,12 @@ static void rna_def_space_outliner(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sort Alphabetically", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_sync_select", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SO_SYNC_SELECT);
RNA_def_property_ui_text(
prop, "Sync Outliner Selection", "Sync outliner selection with other editors");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
/* Granular restriction column option. */
prop = RNA_def_property(srna, "show_restrict_column_enable", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_ENABLE);

View File

@@ -2297,6 +2297,11 @@ static void rna_def_userdef_theme_space_outliner(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Selected Highlight", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "active", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Active Highlight", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "selected_object", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Selected Objects", "");