Compare commits

...

219 Commits

Author SHA1 Message Date
6ae45c0874 Merge branch 'outliner-collection-colors' into soc-2020-outliner 2020-08-20 11:54:52 -06:00
d613d9fec2 Outliner: Fix missing argument to UNUSED macro 2020-08-20 11:52:24 -06:00
37f9b915ac Fix: Line highlight using wrong function 2020-08-20 11:44:13 -06:00
65afd36ed7 Merge branch 'outliner-parent-highlight' into soc-2020-outliner 2020-08-20 11:29:42 -06:00
1d78720e74 Outliner: Parent highlight for collapsed active child
Draw the row highlighted for the parents of a subtree with the active
object when that subtree is collapsed.
2020-08-20 11:28:24 -06:00
538bb8002c Merge branch 'master' into soc-2020-outliner 2020-08-20 11:15:30 -06:00
aff36e4082 Merge branch 'master' into soc-2020-outliner 2020-08-19 19:52:08 -06:00
8eee0a2712 Collections: Add color tagging and use in outliner
Add a color tag to collections and allow tagging from the outliner
context menu.

Show the colored icon in UI menus.

Differential Revision: https://developer.blender.org/D8622
2020-08-18 21:53:04 -06:00
ff8255f159 Collections: Include new collection color icon 2020-08-18 21:47:11 -06:00
093294e167 Collections: Add color tagging & use in outliner
Add a color tag to collections and allow tagging from the outliner
context menu.

Show the colored icon in UI menus.
2020-08-18 21:23:43 -06:00
4beb3c92df Merge branch 'master' into soc-2020-outliner 2020-08-18 20:46:46 -06:00
1cf39ca002 Cleanup: Remove broken context menu mode toggle code
The outliner context menu had an operator to enter/exit modes, but it
only showed when the objects were in modes. Additionally, I'm not
certain how much it was used since it has been broken for a long time
and no one has reported it.

Entering modes through the context menu could be a nice feature, but I
think it would be an easier problem to solve after a context menu
refactor.
2020-08-18 15:50:15 -06:00
347af6aa9d Cleanup: Outliner mode toggle warnings
Remove warnings from unused parameters.
2020-08-18 15:14:48 -06:00
a336b0c3a1 Cleanup: Remove unused outliner select code
No functional changes.
2020-08-18 15:06:45 -06:00
1fc322125d Cleanup: Remove unused tree sort code
No functional changes
2020-08-18 15:01:04 -06:00
d689dd777c Merge branch 'master' into soc-2020-outliner 2020-08-18 14:35:41 -06:00
6e5642afb9 Merge branch 'master' into soc-2020-outliner 2020-08-18 10:10:04 -06:00
282866ad94 Fix build error 2020-08-17 21:08:20 -06:00
d1a7d93ace Merge branch 'soc-2020-outliner' of git.blender.org:blender into soc-2020-outliner 2020-08-17 21:05:55 -06:00
30801617a6 Cleanup: Remove unused outliner code
Some functions that have been rewritten for GSoC 2020 can now be
removed.
2020-08-17 20:54:36 -06:00
550835a73b Outliner: Draw hierarchy lines for child objects
Reintroduce the drawing of hierarchy lines for child objects.
2020-08-17 20:53:28 -06:00
2cf264009e Outliner: Only draw border for active highlight
Drawing the background filled lead to icons with low contrast against
the background. Using a more opaque border solves that issue and is also
more readable.
2020-08-17 20:29:22 -06:00
7900cb3b35 Outliner: Move active highlight code to common function
Drawing the roundrect highlights for icons had duplicate code, move to a
shared function. No functional changes.
2020-08-17 20:08:19 -06:00
63cd866f55 Outliner: Move active highlight code to common function
Drawing the roundrect highlights for icons had duplicate code, move to a
shared function. No functional changes.
2020-08-17 20:03:06 -06:00
965aadd02a Merge branch 'master' into soc-2020-outliner 2020-08-17 09:53:53 -06:00
bec588da8a Outliner: Prevent box select & dragdrop from mode col 2020-08-15 21:36:58 -06:00
d0cf7a3e85 Outliner: Fix crash on id delete collections 2020-08-15 20:56:15 -06:00
2222d445ef Outliner: Remove the set_operation_types function 2020-08-15 20:33:39 -06:00
e0d6c13a44 Outliner: Fix ID operation menu
Use the active item to determine the type of action to take.
2020-08-15 20:25:20 -06:00
4fa4b2742d Outliner: Don't select parent on right click
Parent selection interfered with some actions (like ID delete). Later it
would be good to use the outliner_item_select function, but for now it
causes too many issues.
2020-08-15 20:24:46 -06:00
19525d4a11 Outliner: Cleanup Constraint and Modifier context menu
Rather than trying to infer the type of data to act on, default to
constraints and modifiers respectively. This simplifies the code.

Also a bit of cleanup.
2020-08-15 20:12:02 -06:00
8da9fd000b Outliner: Refactor context menu selection
Use the outliner_item_select function for consistency. Also ensure the
target item is activated so the active can be used in the context menu
operators to identify the type of item to operate on.
2020-08-15 20:05:05 -06:00
0e360a4a2d Cleanup: Use listbase foreach macro 2020-08-15 17:53:43 -06:00
6467d34d00 Outliner: Infer outliner context menu from target element
The context menu tried to determine the type of action based on the
selected elements. This isn't intuitive, rather it should be based on
the target. That way if you have objects and collections selected, a
right click on a collection should show the collection menu.

There is more work to be done, some menus fail to execute properly now
that the old guarantees are gone.
2020-08-15 17:50:09 -06:00
d4dad94db5 Merge branch 'master' into soc-2020-outliner 2020-08-15 16:23:27 -06:00
44d8093f3d Outliner: Move view layer tree left when mode col is disabled 2020-08-14 21:24:33 -06:00
a11a0083b7 Collections: Show icons in search menus
Show in Object Properties > Instancing > Collection and elsewhere.

Remove the link icon in UI_collection_color_icon_get because the link is
redundant in that menu.
2020-08-14 16:43:14 -06:00
12bd445aab Collections: Use filled collection icon in menus
After using colored icons in menus, use normal icon for non-tagged
collections for consistency.
2020-08-14 16:32:11 -06:00
4350ea4ecd Outliner: Simplify collection drop tooltip
Rather than specifying after/before/between for collection reorder, just
use "Reorder collection(s)" similar to object reorder.
2020-08-14 16:27:12 -06:00
a0cd2dbcce Outliner: Add new row children filter
Add a new filter to prevent the drawing of row icons.
2020-08-14 16:24:31 -06:00
ae09b1fdf2 Merge branch 'master' into soc-2020-outliner 2020-08-14 09:52:10 -06:00
cd0f918c1b Collections: Use collection icon for collection color squares
Rather than using a fixed square, draw the filled collection icon. This
looks cleaner, and has the benefit of implying that collection colors
only apply to collections, not to objects or other types.
2020-08-13 22:05:53 -06:00
4c673a6d48 Outliner: Expand modifier panels when clicked in outliner
With properties sync, it makes sense to expand the modifier in the
properties editor on click, otherwise it takes an additional click to
make modifications to the modifier.
2020-08-13 19:23:19 -06:00
d5f3ae7978 Cleanup: Formatting 2020-08-13 19:15:35 -06:00
7c6b8d8db5 Cleanup: Refactor parent bone into shared function 2020-08-13 19:15:05 -06:00
576028db53 Collections: Use 8 colors for color tagging 2020-08-13 17:12:31 -06:00
be10ffb56d Revert "Outliner: Remove outliner parent object selection"
This reverts commit cebafc9854.

While this solution does work, it's not perfect and occasionally breaks,
leaving the outliner in a half-synced state.
2020-08-13 11:40:25 -06:00
6d6ba343dd Fix: Outliner mode column preventing element expansion
Elements in modes other than Scenes or View Layer could not be expanded
when the mode column was enabled. Just an oversight on the selection
pass through.
2020-08-13 11:37:10 -06:00
ecca5bbfc9 Merge branch 'master' into soc-2020-outliner 2020-08-13 10:20:44 -06:00
41d9e3dd68 Fix: Use shift for bone restrict button hierarchy toggles
The bone restrict buttons were using `ctrl` rather than `shift` for the
hierarchy toggle. Use `shift` for consistency.
2020-08-12 17:22:50 -06:00
c8eaede01d Collection: Show color icon for Remove from collection menu 2020-08-12 16:54:14 -06:00
6a2c968c00 UI: Move collection color icon function
Just a cleanup to reduce repetition.
2020-08-12 16:53:55 -06:00
0518c9d582 Collections: Show color tags in object.collection_link
Add a case to rna_id_itemf to add collection color tags. It may be
better to create a separate function, but it works okay for now.
2020-08-12 16:29:23 -06:00
bec2fad215 Collections: Show correct icon for move to collection submenus
The submenu would show the scene data icon for the first entry in each
submenu rather than using the collection color icon.
2020-08-12 16:14:23 -06:00
280404f0a1 Collections: Fix collection colors in move/link menu
The colors would not draw for items at a root in the collection tree
2020-08-12 16:14:10 -06:00
1c5f46d293 Merge branch 'master' into soc-2020-outliner 2020-08-12 15:20:49 -06:00
da3cf18514 Merge branch 'master' into soc-2020-outliner 2020-08-08 10:37:20 -06:00
1b285bc43b Collections: Add color tags to move and link menus 2020-08-07 22:28:13 -06:00
698cde9344 Merge branch 'master' into soc-2020-outliner 2020-08-07 15:36:04 -06:00
8891cc2a1b Outliner: Prevent color tag on linked collections 2020-08-07 09:51:54 -06:00
90c60bb0ce Outliner: Show mode icon on hover
Swap the dot out for the mode icon on hover. Based on studio feedback.
Not sure if it should be only hover on the icon, or hover on the whole
row.
2020-08-06 13:59:31 -06:00
8e483b44e7 Outliner: Remove "Color Tag" label 2020-08-06 13:59:19 -06:00
43cc3fb17d Outliner: Show Mode Column by default 2020-08-06 13:53:25 -06:00
63ba4633d1 Outliner: Fix bone constraint selection not activating bone
If the clicked constraint is a bone, the parent bone should be activated
to ensure the properties tab switch works.
2020-08-06 11:30:41 -06:00
3990b8edae Cleanup: Use utility function for outliner context menu
Rather than looping over the tree, use the existing function to find the
element at the y coordinate of the click.

Also cleanup the function arguments which has the nice effect of fixing
the broken reports.
2020-08-06 10:06:22 -06:00
fd221ce385 Merge branch 'master' into soc-2020-outliner 2020-08-06 09:26:12 -06:00
a6f4dbd6cb Fix: Wrong offset for collection rename button
After moving the collection exclude checkbox to the restrict columns the
rename field drew with an additional offset. Remove the offset.
2020-08-05 21:32:43 -06:00
214223e864 Outliner: Use solid collection icon
Switch to the solid collection icon (already on the sheet) for the
collection colors. Perhaps use the solid for colored collections, and
the lines for non-colored?
2020-08-05 21:30:44 -06:00
15e59f4640 Outliner: Revert back to 6 collection colors
Until better colors are decided on, 6 is plenty.
2020-08-05 14:44:29 -06:00
6c7d4bf72d Merge branch 'master' into soc-2020-outliner 2020-08-05 08:11:04 -06:00
5f8d7ad5b2 Merge branch 'master' into soc-2020-outliner 2020-08-04 12:21:13 -06:00
0ead199713 Merge branch 'master' into soc-2020-outliner 2020-08-04 09:33:21 -06:00
ba778a64b9 Outliner: Prevent setting scene collection color tag
If the scene collection was included in the selection, it would be set
to the collection color. The scene collection shouldn't be allowed a
tag.
2020-08-03 21:44:34 -06:00
66a8ec44c7 Cleanup: Add TODO comment 2020-08-03 20:27:30 -06:00
247372cbe7 Merge branch 'master' into soc-2020-outliner 2020-08-03 17:33:13 -06:00
066f78e8f9 Merge branch 'master' into soc-2020-outliner 2020-08-03 14:08:46 -06:00
53452c452f Outliner: Activate objects with mode toggle buttons
This fixes the case where a mode toggle on the active object would
remove all objects from that mode.
2020-07-30 16:33:06 -06:00
aef6b5d10c Outliner: Draw collection icon as colored
There were too many issues filling behind the collection icon, such as
the active box that draws was conflicting. This is safer to color just
the icon. We do need a different icon though.
2020-07-30 13:11:42 -06:00
ec57e6c790 Outliner: Fix crash opening scenes view
The collection enable box should only show in scenes view.
2020-07-29 19:45:00 -06:00
5290d7e79f Cleanup: Add TODO comments 2020-07-29 16:41:13 -06:00
19557d0d82 Merge branch 'master' into soc-2020-outliner 2020-07-29 16:41:06 -06:00
601ce87b1a Fix: Incorrect context menu after merge
Accidentally resolved merge conflicts wrong.
2020-07-27 21:38:24 -06:00
1c53386124 Merge branch 'master' into soc-2020-outliner 2020-07-27 21:36:21 -06:00
6eb096d80a Outliner: Fix wrong offset for row highlights
The row highlight on the right was slightly cut off.
2020-07-27 16:11:56 -06:00
814771e316 Outliner: Move collection enable icon to restrict column
The checkbox behaves as a restriction button, and drawing it vertically
in the restriction column allows easier click+drag support.

This also removes clutter from the mode column.
2020-07-27 15:55:47 -06:00
14f1a0ae7c Merge branch 'master' into soc-2020-outliner 2020-07-27 14:16:00 -06:00
96173be437 Fix: Outliner small select sync issue with dragdrop
Dragdrop in the outliner would sync from objects rather than to objects.
This led to strange results when dragging child data. i.e. a modifier
drag would select the parent object in the outliner.

This requires not storing the dragged tree element because the tree is
rebuilt between the initial drag and the drop, causing heap use after
free.

Perhaps the outliner can be flagged to not rebuild on selection events.
2020-07-25 17:17:12 -06:00
2832b37e8e Outliner: Fix missing select sync on editmode toggle 2020-07-25 16:13:05 -06:00
cee0d1921f Merge branch 'master' into soc-2020-outliner 2020-07-25 14:09:32 -06:00
3815452e47 Outliner: Add uistack shaderfx copy
This finishes the uistack drop operator.
2020-07-25 14:03:20 -06:00
b178a1c9ca Outliner: Add constraint copy all
Dragging the TSE_CONSTRAINT_BASE to another object or bone will copy all
of the constraints to the target from the source.
2020-07-25 12:10:41 -06:00
bc6bdf5b79 Cleanup 2020-07-25 12:00:18 -06:00
715f94d55b Outliner: Fix uistack reorder edge case
Fix the edge case where reorder would occasionally move to the wrong
index.
2020-07-25 11:45:11 -06:00
488134c80e Cleanup: Outliner UIstack reorder 2020-07-25 11:37:35 -06:00
e2febd8168 Outliner: Fix dragdrop insert not working for childless elements
Childless elements are flagged as open, so sorting after does not work.
An additional check to see if there are any children is neded.
2020-07-24 16:44:04 -06:00
19d5d339d2 Merge branch 'master' into soc-2020-outliner 2020-07-24 16:11:34 -06:00
cebafc9854 Outliner: Remove outliner parent object selection
In order to fix T74332 it was necessary to flag parent elements as
selected in the outliner to prevent the bases from being deselected on
the selection sync. This ensures the parent object is selected for
editing drivers, etc.

An annoying issue that results from this is the context menu shows
Object entries even when the target is a data (material, action, bone)
type. This also causes issues with drag and drop and other operations.

This adds a new TSE flag to prevent a selection sync on a per-element
case. This is used to prevent a parent element sync which ensures the
parent object stays selected, but it does not draw as selected in the
outliner.
2020-07-23 21:33:23 -06:00
a3fd574a74 Merge branch 'master' into soc-2020-outliner 2020-07-23 21:03:51 -06:00
04f969627d Outliner: Sort bones alphabetically 2020-07-22 14:48:17 -06:00
ba46eeff75 Outliner: Cleanup sorting 2020-07-22 14:48:05 -06:00
3d3ef71a39 Merge branch 'master' into soc-2020-outliner 2020-07-22 13:59:46 -06:00
0027319690 Outliner: Bone constraint drag&drop
Support bone constraints for drag and drop. A few issues still exist:
* Indices for all types for reorder aren't always correct.
* Bones are "supported" for modifiers and shader effects when they
  shouldn't be.
2020-07-21 19:14:13 -06:00
3ceebff60b Outliner: Fix uistack reorder highlights 2020-07-20 16:31:11 -06:00
3d197d30ec Merge branch 'master' into soc-2020-outliner 2020-07-20 08:19:10 -06:00
b7b2386cff Outliner: Add generic UI Stack drop operator
Replaces the modifier drop operator and works for modifiers,
constraints, and shader fx. Because these three elements share common
traits, it made the code simpler to combine the operator for all three.
Three types of actions are supported depending on where the element is
dropped:
* Drop within the same list to reorder.
* Drop on another object to copy.
* Drop the base (parent) element to link all to another object.

A few cases are yet unsupported but will be added to blenkernel.
2020-07-18 21:49:39 -06:00
7231cc5414 Outliner: Remove creation order sort method
This was a placeholder while manual sort did not work. Manual sort
changes the "creation order" in the database lists so creation order was
the same ordering as manual.
2020-07-18 16:43:27 -06:00
7faebce414 Outliner: Add modifier copy with drag and drop
Allow copying single modifiers with drag and drop between objects. The
next step is to generalize the code for modifiers and use it for
contraints, modifiers, and shaderfx.
2020-07-18 11:43:35 -06:00
fe80f9c8d1 Merge branch 'master' into soc-2020-outliner 2020-07-18 08:40:19 -06:00
d00b886bfd Outliner: Add gpencil effect props sync
Add properties tab sync when gpencil shader effects are selected.
2020-07-17 16:24:28 -06:00
e74b428d41 Outliner: Draw gpencil shader effects in the tree
Draw the gpencil visual shaders in the outliner tree. Adds new TSE
types.
2020-07-17 16:20:46 -06:00
301f59a839 Outliner: Draw Gpencil modifiers in the tree
The outliner icon code had cases for grease pencil modifiers but the
modifiers did not actually draw.

Some icons are incorrect:
* Multiple Strokes
* Texture Mapping
2020-07-17 16:17:01 -06:00
7a72f9b9f6 Merge branch 'master' into soc-2020-outliner 2020-07-17 15:21:35 -06:00
a5f4086e86 Outliner: Draw collection icons in a row 2020-07-17 15:16:52 -06:00
8e972bf72b UI: Fix drawing of aligned buttons in menu rows
This adds support for drawing icon buttons as a row in a popup menu. This is needed for drawing collection color tag icons in a row in the outliner context menu.

A few issues still exist, but I would like some initial review now that it mostly works.
* The icons do not draw aligned with the text labels. This is easy to fix, but the hover highlight is still drawn incorrectly.
* This works well when creating row icon buttons with an operator_enum, but manually creating the row elements doesn't draw an initial offset blank icon.

Differential Revision: https://developer.blender.org/D8317
2020-07-16 11:38:00 -06:00
c122597bf7 Merge branch 'master' into soc-2020-outliner 2020-07-16 11:37:25 -06:00
c4f23e1404 Merge branch 'master' into soc-2020-outliner 2020-07-16 08:12:13 -06:00
47a3013d68 Collection Colors: Change defaults 2020-07-15 17:22:12 -06:00
982e795013 Collection Colors: Add 4 new color slots 2020-07-15 17:08:03 -06:00
45d27e39e0 Collection Tags: Use numbers rather than fixed color names 2020-07-15 16:58:33 -06:00
c3edf375c2 Outliner: Cleanup collection color preferences
Cleanup the excess labels and code.
2020-07-15 16:15:50 -06:00
06928a7a4c Merge branch 'master' into soc-2020-outliner 2020-07-15 08:26:44 -06:00
51ce1255de Outliner: Draw highlights as roundrects
This is an experiment to make the selection status more consistent
between the outliner, file browser, and UI lists.
2020-07-14 20:30:28 -06:00
5aa9a4f46a Outliner: Fix bases out of sync on object drop 2020-07-14 19:48:02 -06:00
27177d84e8 Merge branch 'master' into soc-2020-outliner 2020-07-13 14:27:55 -06:00
7e83200003 Outliner: Fix modifier drop index
Make modifier drop more consistent.
2020-07-09 19:58:03 -06:00
e269f4bfca Outliner: Only allow object drop over name or icon
When doing object drop, allow collection drop when dropping outside the
name or icon, and parent drop when over name or icon.
2020-07-09 17:25:37 -06:00
3c39c51d02 Outliner: Object drop initial implementation
Allow reordering objects in the outliner. Works for multiple selection.
The code has a few places that could be cleaned up.

Also, an issue exists where it isn't always clear where to move the
objects to. This applies to any outliner drag+drop so that will be
handled separately.
2020-07-09 13:40:58 -06:00
b034849e63 Merge branch 'master' into soc-2020-outliner 2020-07-09 10:37:51 -06:00
e59db98688 Outliner: Add type options for new collections
Add options to move or link objects into the new collection from the
context menu.
2020-07-08 21:23:24 -06:00
35a01f85e8 Outliner: Create new collection from selected objects 2020-07-08 21:09:46 -06:00
7269eba111 Outliner: New Collection Menu 2020-07-08 21:09:46 -06:00
c4e2d23702 Outliner: Activate collections with selection
Restore original behavior.
2020-07-08 21:09:11 -06:00
c4d6f0c0f2 Outliner: Move collection colors from submenu
The goal is to draw them on a single line, perhaps a template is needed
here.
2020-07-08 17:18:05 -06:00
6ac79a7dfb Outliner: Remove need to hold shift when parenting
https://developer.blender.org/D3812 discussed reasons why holding shift
to parent was needed. Now in the outliner we show child-parent
relationships clearly in View Layer mode so this extra modifer key is
not needed.

When dropping over an object name the parent operator is used, and when
dropping anywhere outside the object name will move to collection.
2020-07-08 14:26:29 -06:00
6140d22af3 Outliner: Disable collection reorder when sorted
Disable reordering collections in the outliner when not in manual sort
mode.
2020-07-08 14:26:29 -06:00
2d2491dd81 Merge branch 'master' into soc-2020-outliner 2020-07-08 14:26:11 -06:00
7186d8117a Merge branch 'master' into soc-2020-outliner 2020-07-07 10:31:18 -06:00
263e2537c5 Outliner: Add sort by object type
When sorting by type, collections are sorted alphabetically. Objects are
sorted by their types.
2020-07-06 17:41:22 -06:00
3155fa19c5 Outliner: Sort collection and object names
Refactor the sorting code to apply to collections and objects, but keep
the order between objects and collections separate for now.
2020-07-06 17:00:09 -06:00
9d2e660643 Outliner: Add sort method enum
Replace the SO_SKIP_SORT_ALPHA with an enum of multiple sort types. The
types are manual, alphabetical, type, and creation order. Only
alphabetical works.
2020-07-06 16:58:08 -06:00
c87f9ac840 Merge branch 'master' into soc-2020-outliner 2020-07-06 13:19:11 -06:00
7fdc6c5ca6 Outliner: Modifier drop link and cleanup
Allow drag and drop from modifier base to another object to link
modifiers. Also clean up the code.

There are still issues with the modifier reorder.
2020-07-04 16:37:57 -06:00
561bd0ebac Collection Colors: Fill behind
It is easy to switch with the #if blocks now.
2020-07-04 11:48:37 -06:00
4ac06b97ee Merge branch 'master' into soc-2020-outliner 2020-07-04 11:38:50 -06:00
f5a22d4bbd Collection Colors: Color collection icons
Color the collection icons rather than drawing behind.
2020-07-04 11:37:40 -06:00
680b2a4901 Collection Colors: Disable background drawing
Try icon coloring again.
2020-07-04 11:25:03 -06:00
cd3d261e3c Outliner modifier drop
Initial implementation. Experimentation to see what types of data
are needed.
2020-07-03 20:56:42 -06:00
abf079b64e Revert "Collection Colors: Change indices"
This reverts commit 05ddacc342.

Collections were defaulted to colored and I wasn't sure if it was best
to handle the off by one indexing in a few cases or do versioning.
2020-07-03 15:44:15 -06:00
05ddacc342 Collection Colors: Change indices
Use -1 for no color to utilize better themes indexing.
2020-07-03 15:30:24 -06:00
b134a0c491 Outliner: Fix collection hierarchy lines
There were a couple of cases where the hierarchy lines didn't draw. This
refactors the code to be simpler and cover all the cases.
2020-07-03 14:42:32 -06:00
3a7101f9e8 Merge branch 'master' into soc-2020-outliner 2020-07-03 14:01:15 -06:00
b485592901 Theme: Add theming for collection colors
Add a new panel similar to the Bone Color Sets panel to set the
collection colors. These draw in the outliner and outliner context menu.
2020-07-02 21:27:04 -06:00
cf97bd606e Collection Colors: Add icons
Add square icons for collection color tags. These are still using
hard-coded colors but it would be easy to add them to the themes now.
2020-07-02 20:05:08 -06:00
693c168c8a Merge branch 'master' into soc-2020-outliner 2020-07-02 17:04:40 -06:00
0f8678b536 Outliner: Draw collection hierarchy lines
Rather than drawing lines for object hierarchies, draw for collections.
These lines will be colored when collections are colored.

There are still small issues with the implementation, but it works quite
well for now.

The dashed lines for child objects (not in collection) are removed but
could be brought back.
2020-07-01 21:28:27 -06:00
def6f13b77 Fix: Add drag lock to mode column icons
Allow "sloppy" drag over the column
2020-07-01 17:27:03 -06:00
05da610ee7 Outliner: Draw collection color behind icon
Rather than coloring the icon itself and drawing a bar to the left, draw
a roundbox behind the collection icon. This has the benefit of being
small but still easily noticed.

Two downsides that need to be addressed:
1. The active collection highlight is not shown. This needs to be
   refactored anyway for all types because it is not always easy to tell
   which items are active.
2. Hierarchies are not colored.
2020-07-01 17:13:29 -06:00
1bb6d5cd75 Mode Column: Move collection checkbox to mode column
To make the hierarchy more clear, draw the collection exclude icons in
the left column. While this is nice, it makes the mode toggle column
very messy in non-object modes. Will look into that later.
2020-07-01 17:02:46 -06:00
a0931a5a70 Outliner: Remove data activation columns
This column is no longer part of the plan.
2020-07-01 16:54:38 -06:00
e7123ab148 Merge branch 'master' into soc-2020-outliner 2020-07-01 16:30:38 -06:00
fdd643ebb6 Merge branch 'master' into soc-2020-outliner 2020-06-30 11:13:36 -06:00
07e11e5af2 Cleanup: rename left column to mode column 2020-06-29 20:43:34 -06:00
4947aff2b9 Outliner: Autoscroll on drag and drop
Scroll the view when dragging elements near the borders. This works in
all 4 directions. Uses the VIEW2D_OT_edge_pan operator.
2020-06-29 20:24:57 -06:00
086cad7624 Merge branch 'master' into soc-2020-outliner 2020-06-29 16:25:21 -06:00
95abb9967b Collection Colors: Lighter colors and combined bar and icon
Use more consistent colors, and draw a line and the collection icon
itself.
2020-06-26 16:25:28 -06:00
ac24ce26b2 Merge branch 'master' into soc-2020-outliner 2020-06-26 14:01:59 -06:00
80bdeffac4 Outliner: Colored collection icons
Draw the collection icons in the outliner. This may be changed in the
future.
2020-06-25 20:43:56 -06:00
d99682c6ba Collections: Add ability to set color tag from the outliner 2020-06-25 20:43:56 -06:00
0fcf476f04 Collection Colors DNA and RNA 2020-06-25 20:43:56 -06:00
fc08a33223 Merge branch 'master' into soc-2020-outliner 2020-06-25 11:17:54 -06:00
9e39bb2dbc Merge branch 'master' into soc-2020-outliner 2020-06-22 09:43:43 -06:00
75a9ba558e Cleanup: Use psys function 2020-06-20 17:01:44 -06:00
0eb4d9445a Merge branch 'master' into soc-2020-outliner 2020-06-20 16:39:09 -06:00
c7e5493b15 Outliner: Properties sync with pinned data
Previously only the type of tab/context was passed to the properties
editor from the outliner. This caused some issues. If Object A was
pinned, and Object B's mesh data was clicked, it would switch to Object
A's mesh data.

Now pass an RNA pointer along to verify if the outliner data is in the
valid path when the properties editor is pinned.

Also support Hair and PointCloud new object types.
2020-06-20 14:40:42 -06:00
93189c4e08 Cleanup: Move functions 2020-06-19 22:02:10 -06:00
e36dd0b7cf Properties: Handle most pinned types from outliner 2020-06-19 21:56:06 -06:00
096cd76aa2 Outliner: Use proper icon for fake users
In orphan data display mode, the QUIT and X icons were used to show the
state of fake users. This uses the proper icons, and removes the "F"
column now that we have a proper icon to show the fake user status.
2020-06-19 20:16:30 -06:00
1d8a5b3772 Fix Mode column offset in orphan mode
Was improperly treating the display mode as a bit flag
2020-06-19 19:53:53 -06:00
9aa09d65c1 Cleanup: Unused 2020-06-19 13:22:17 -06:00
0bf5db9040 Merge branch 'master' into soc-2020-outliner 2020-06-19 13:05:12 -06:00
750d184812 Merge branch 'master' into soc-2020-outliner 2020-06-18 21:56:46 -06:00
13dd9eeb25 Outliner: Add properties sync for most types
Add properties sync for all types that have a context tab. Some may have
been missed but they can be added later easily.
2020-06-18 21:19:06 -06:00
c87b8d0494 Remove proof-of-concept properties sync 2020-06-18 21:14:33 -06:00
479aaccc93 Add mesh to properties sync 2020-06-17 20:51:27 -06:00
a50f87d4b6 Disable camera and scene toggle 2020-06-17 20:51:13 -06:00
8451c5d5e0 Merge branch 'master' into soc-2020-outliner 2020-06-17 20:38:09 -06:00
bd1e3440fe Properties sync for more types
This might be easier to add in a more generic way later
2020-06-17 16:21:10 -06:00
1fb733ca74 Don't swap tabs if properties editor is pinned 2020-06-17 14:30:47 -06:00
1764f5b24d Only switch tabs for visible properties editors
Instead of iterating over each Space in the area, only update the first
in the list which is the currently visible one. This prevents updating
the properties editor when it is not currently visible.
2020-06-17 13:46:19 -06:00
34e4dbec33 Merge branch 'master' into soc-2020-outliner 2020-06-17 09:08:59 -06:00
cfcba6574e Outliner: Add initial support for properties tab switch
When selecting datablocks from the outliner, switch the properties
editor to the relevant tab.

This is a very basic proof of concept implementation.
2020-06-16 22:02:27 -06:00
bccfbc1b2d Merge branch 'master' into soc-2020-outliner 2020-06-15 17:02:20 -06:00
6fbf342e82 Outliner: Fix mode column when lock object modes is disabled
When Lock Object Modes was disabled, multiple objects would be shown as
in the interaction mode even though only one object could be edited at a
time. This was not an issue for edit and pose mode because those modes
support multi object editing. But in modes like sculpt it implied that
multiple objects could be edited at the same time.

This only draws the active icon for the active object when lock object
modes is disabled, and when there is no active edit or pose object.
2020-06-15 16:57:58 -06:00
7d51351004 Outliner: Use dot icons for object not in current interaction mode
Revert the change that used a faded-out icon of the mode. That was too
cluttered.
2020-06-15 16:18:52 -06:00
ed54ee3bac Outliner: Remove camera and collection activation on selection
Now that the left column works well for data activation, remove the
albility to activate by clicking the collection or camera data itself.
2020-06-13 15:29:54 -06:00
a36495e72d Cleanup: Add new callback for mode toggle
Instead of sharing the same callback fn for data activation and mode
toggle in the buttons, split into two similar functions to better
differentiate which action should be done.

This also fixes the issue where clicking a data activation radio button
would enter the mode toggle function instead.
2020-06-13 15:20:26 -06:00
b09e0f8abe Outliner: Add mode switching to remaining modes in left column
When in modes other than edit or pose, icons are drawn next to each
object in the outliner that also supports the same mode. When the icon
is clicked, that object is activated and swapped into that edit mode.

When Lock Object Modes is disabled and objects are left in their modes,
the icons all draw as if they were simultaneously in that mode. This is
the only issue currently, otherwise it seems to work well.
2020-06-13 14:32:23 -06:00
7a5ed7cc78 Cleanup: Add name to TODO comments 2020-06-13 14:08:18 -06:00
05861f4b59 Outliner: Use faded mode icon instead of dot
In the left column, use the same icon as the objects in the interaction
mode for the buttons to switch that object into the same interaction
mode.
2020-06-13 13:17:10 -06:00
4af045fbef Outliner: Show icons for all interaction modes
When not in object mode, show the interaction mode next to the object in
the outliner. Also show a dot next to each icon that could be switched
into the current mode.

Currently this still only works for edit and pose mode. Seeing the icon
next to the object in the mode is already useful. One issue is that
grease pencil mode icon draws green.
2020-06-12 17:22:41 -06:00
64f74fc94e Merge branch 'master' into soc-2020-outliner 2020-06-12 15:17:17 -06:00
8113a8b0f6 Outliner: Add pose mode toggle to left column
Allow adding/removing objects from pose mode through the left column.
Also cleanup the icon drawing code by using the same function for
active and inactive states and only change the icon and add the callback
when needed.
2020-06-11 19:47:24 -06:00
b69f1ff119 Outliner: Show pose mode toggle icons and always active icons
Toggling these enters edit mode, will fix. Also always show the active
data icons in the outliner.
2020-06-11 11:22:13 -06:00
53c61d2a4c Outliner: Remove mode toggling on selection
Mode toggle was tied to selection. This is the final commit removing
that logic from the OUTLINER_OT_item_activate function.
2020-06-11 11:20:35 -06:00
78944dcadd Outliner: Add activation and toggle to left column buttons
The buttons in the left column didn't work, and in the first step that
they did work, I only added support for camera objects. This adds
support for edit mode toggling and collections and scene activation.
Previously clicking in the column for those types would crash.
2020-06-11 09:11:14 -06:00
7096d1b730 Merge branch 'master' into soc-2020-outliner 2020-06-10 21:39:32 -06:00
490d444097 Outliner: Add walk navigation left and right
Support walk navigation up and down the tree by pressing the left and
right arrows. When holding shift (to toggle expand/collapse on all
children) walking is never done.

When walking right, open the tree if it is closed, or walk into the tree
if it is opened. When walking left, close the tree if it is open, or
select the parent element when closed.
2020-06-10 21:36:58 -06:00
45ee485703 Outliner: Try using radio button icons
Use radio button icons over the dot and check in the outliner.
2020-06-10 21:30:29 -06:00
cb2b5da12d Outliner: Pass tselem instead of te to button functions
When adding callback functions to icon buttons in the outliner, don't
pass the tree element as a pointer because the pointer address changes
between redraws. Instead, pass the tree store element, or pass the data
that is needed.
2020-06-10 20:57:02 -06:00
ef48790804 Merge branch 'master' into soc-2020-outliner 2020-06-08 09:08:19 -06:00
f0caf178d0 Outliner: Add edit mode toggle from left column
When in edit mode, compatible objects are shown next to a dot icon in
the outliner. These objects can then be toggled into the current edit
mode. When the active object is toggled out of edit mode, all objects
are removed from edit mode.

This currently has a few issues:
* Selection is not synced. Adding an object to edit mode selects it, and
  removing deselects it. This needs to be reflected in the outliner.
* This works for all types that support edit mode with two
  issues/exceptions:
** Grease Pencil edit mode is not supported (perhaps grease pencil needs
a small update)
** Text objects support multi-edit, but it doesn't actually allow you to
edit both objects.

The issues need to be fixed in the related mode-code, not the outliner.
It would be nice to fix so the outliner doesn't have to have cases to
not allow Text and Grease Pencil mode.
2020-06-06 12:14:55 -06:00
86ce6c9280 Outliner: Draw icons for edit mode
The end goal is to support all interaction modes, but since edit mode
was already supported in the outliner, it makes sense to start here.

This code takes the current active object and determines it's mode. If
it is in edit mode, then the icons are drawn. This only works for
objects of the same type for now.
2020-06-06 11:39:37 -06:00
e9d621e16e Outliner: Use outliner_item_select for activation
Use outliner_item_select for outliner activation. This is used in a few
places so far and could easily be extended to other operators.

outliner_item_select takes 3 booleans, select, activate, and extend and
properly sets the TSE_SELECTED and TSE_ACTIVE flags based on the bools.

Future commits will move other selection and activation logic to be in
this function.

No functional changes. Separate the mode toggling logic from the
item activation code because these are distinct behaviors. This will
make later changes easier to make, and also makes it possible to
activate on walk select without toggling modes.

Also rename functions to make purpose more clear.
2020-06-06 11:03:09 -06:00
3eea51f6b5 Merge branch 'master' into soc-2020-outliner 2020-06-06 10:59:17 -06:00
82b1cd464e Outliner: Allow setting active data from column
Add a function to set active data from the outliner column on click. The
supported types are collections, cameras, and scenes as these types are
more "disruptive" and change the state of the scene.

For now this is set from the (cluttered) outliner selection function. I
think it would be best to attach to the drawn UI buttons, but currently
they don't want to work with attached functions.
2020-06-06 10:48:12 -06:00
8db03500d7 Outliner: Show active check for scenes and collections
Show the check in the left columns for scenes and collections.

Also remove the ability to set by clicking on the dots because the UI
buttons don't seem to want to activate a callback and have a reasonable
clickable area.
2020-06-06 10:17:20 -06:00
fc7c19c9ab Outliner: Add buttons to set active camera
Add buttons to the left column to set the active camera. The active
camera currently shows a check, and other cameras draw a dot.

For some reason the dot doesn't have a proper hitbox area.

Right now the function to set the camera is done from button callbacks,
but this could also easily be done from outliner_select.c.
2020-06-05 16:44:39 -06:00
661ee21e69 Outliner: Draw left column for activation/mode toggle
In Scenes view mode, a column is added when the toggle is enabled. In
view layer mode, the scene collection has a space next to it where a
expand/collapse triangle could be drawn, so this also offsets the tree a
unit to the left when in view layer display mode.
2020-06-05 13:42:59 -06:00
f2a4dd4d27 Outliner: Add property to show the left column
Add a property to show the left column for the activate/mode toggle
buttons. This needs versioning to apply to the default scene.
2020-06-05 11:44:51 -06:00
56 changed files with 2303 additions and 1045 deletions

View File

@@ -1101,6 +1101,32 @@ const bTheme U_theme_default = {
.active = RGBA(0x000000ff),
},
},
.collection_color = {
{
.color = RGBA(0xe4312bff),
},
{
.color = RGBA(0xef7e42ff),
},
{
.color = RGBA(0xe4dd52ff),
},
{
.color = RGBA(0x9ac546ff),
},
{
.color = RGBA(0x46bcc2ff),
},
{
.color = RGBA(0x8b65dcff),
},
{
.color = RGBA(0x999999ff),
},
{
.color = RGBA(0x06d4432ff),
},
},
};
/* clang-format on */

View File

@@ -68,7 +68,7 @@ class OUTLINER_HT_header(Header):
sub.prop(space, "filter_id_type", text="", icon_only=True)
if display_mode == 'VIEW_LAYER':
layout.operator("outliner.collection_new", text="", icon='COLLECTION_NEW').nested = True
layout.operator("outliner.collection_new", text="", icon='COLLECTION_NEW')
elif display_mode == 'ORPHAN_DATA':
layout.operator("outliner.orphans_purge", text="Purge")
@@ -208,7 +208,7 @@ class OUTLINER_MT_collection(Menu):
space = context.space_data
layout.operator("outliner.collection_new", text="New").nested = True
layout.operator("outliner.collection_new", text="New")
layout.operator("outliner.collection_duplicate", text="Duplicate Collection")
layout.operator("outliner.collection_duplicate_linked", text="Duplicate Linked")
layout.operator("outliner.id_copy", text="Copy", icon='COPYDOWN')
@@ -239,6 +239,10 @@ class OUTLINER_MT_collection(Menu):
if space.display_mode == 'VIEW_LAYER':
layout.separator()
layout.menu("OUTLINER_MT_collection_view_layer", icon='RENDERLAYERS')
layout.separator()
row = layout.row(align=True)
row.operator_enum("outliner.collection_color_tag_set", "color", icon_only=True)
layout.separator()
@@ -254,7 +258,7 @@ class OUTLINER_MT_collection_new(Menu):
@staticmethod
def draw_without_context_menu(context, layout):
layout.operator("outliner.collection_new", text="New Collection").nested = True
layout.operator_menu_enum("outliner.collection_new", "type", text="New Collection")
layout.operator("outliner.id_paste", text="Paste Data-Blocks", icon='PASTEDOWN')
def draw(self, context):
@@ -293,21 +297,11 @@ class OUTLINER_MT_object(Menu):
layout.separator()
if object_mode in {'EDIT', 'POSE'}:
name = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode].name
layout.operator("outliner.object_operation",
text=iface_("%s Set", i18n_contexts.operator_default) % name).type = 'OBJECT_MODE_ENTER'
layout.operator("outliner.object_operation",
text=iface_("%s Clear", i18n_contexts.operator_default) % name).type = 'OBJECT_MODE_EXIT'
del name
layout.separator()
if not (space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection):
layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK'
layout.separator()
layout.operator("outliner.collection_new", text="New Collection").nested = True
layout.operator("outliner.collection_new", text="New Collection")
layout.separator()
@@ -351,13 +345,18 @@ class OUTLINER_PT_filter(Panel):
if display_mode != 'DATA_API':
col = layout.column(align=True)
col.prop(space, "use_sort_alpha")
col.label(text="Sort by")
col.prop(space, "sort_method", expand=True)
layout.separator()
row = layout.row(align=True)
row.prop(space, "use_sync_select", text="Sync Selection")
layout.separator()
row = layout.row(align=True)
row.prop(space, "show_mode_column", text="Show Mode Column")
layout.separator()
col = layout.column(align=True)
col.label(text="Search:")
col.prop(space, "use_filter_complete", text="Exact Match")
@@ -389,6 +388,9 @@ class OUTLINER_PT_filter(Panel):
row = sub.row()
row.label(icon='BLANK1')
row.prop(space, "use_filter_children", text="Object Children")
row = sub.row()
row.label(icon='BLANK1')
row.prop(space, "use_filter_row_children", text="Row Children")
if bpy.data.meshes:
row = sub.row()

View File

@@ -1019,6 +1019,24 @@ class USERPREF_PT_theme_bone_color_sets(ThemePanel, CenterAlignMixIn, Panel):
flow.prop(ui, "active")
flow.prop(ui, "show_colored_constraints")
class USERPREF_PT_theme_collection_colors(ThemePanel, CenterAlignMixIn, Panel):
bl_label = "Collection Colors"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, _context):
layout = self.layout
layout.label(icon='GROUP')
def draw_centered(self, context, layout):
theme = context.preferences.themes[0]
layout.use_property_split = True
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
for i, ui in enumerate(theme.collection_color, 1):
flow.prop(ui, "color", text=iface_(f"Color {i:d}"), translate=False)
# Base class for dynamically defined theme-space panels.
# This is not registered.
@@ -2254,6 +2272,7 @@ classes = (
USERPREF_PT_theme_interface_icons,
USERPREF_PT_theme_text_style,
USERPREF_PT_theme_bone_color_sets,
USERPREF_PT_theme_collection_colors,
USERPREF_PT_file_paths_data,
USERPREF_PT_file_paths_render,

View File

@@ -100,6 +100,10 @@ void BKE_collection_object_move(struct Main *bmain,
struct Collection *collection_dst,
struct Collection *collection_src,
struct Object *ob);
void BKE_collection_object_move_after(struct Main *bmain,
struct Collection *collection,
struct Object *ob_relative,
struct Object *ob);
bool BKE_scene_collections_object_remove(struct Main *bmain,
struct Scene *scene,

View File

@@ -77,6 +77,10 @@ bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
bool BKE_object_link_modifier(struct Object *ob_dst,
const struct Object *ob_src,
struct ModifierData *md);
bool BKE_object_link_gpencil_modifier(struct Object *ob_dst, struct GpencilModifierData *md);
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob, const int flag);
void BKE_object_free_shaderfx(struct Object *ob, const int flag);

View File

@@ -181,6 +181,7 @@ void BKE_shaderfx_copydata(struct ShaderFxData *fx, struct ShaderFxData *target)
void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
struct ShaderFxData *target,
const int flag);
void BKE_shaderfx_copy(struct ListBase *dst, const struct ListBase *src);
void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
bool BKE_shaderfx_has_gpencil(struct Object *ob);

View File

@@ -1118,6 +1118,38 @@ void BKE_collection_object_move(
}
}
/**
* Move object within a collection after specified object.
*
* For outliner drag & drop.
*/
void BKE_collection_object_move_after(Main *bmain,
Collection *collection,
Object *ob_relative,
Object *ob)
{
if (ELEM(NULL, collection, ob_relative, ob)) {
return;
}
CollectionObject *relative = BLI_findptr(
&collection->gobject, ob_relative, offsetof(CollectionObject, ob));
if (!relative) {
return;
}
int index_to = BLI_findindex(&collection->gobject, relative);
CollectionObject *object = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
if (!object) {
return;
}
int index_from = BLI_findindex(&collection->gobject, object);
BLI_listbase_move_index(&collection->gobject, index_from, index_to);
BKE_main_collection_sync(bmain);
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -689,6 +689,60 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return false;
}
bool BKE_object_link_modifier(struct Object *ob_dst, const struct Object *ob_src, ModifierData *md)
{
ModifierData *nmd = NULL;
if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
return false;
}
if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
return false;
}
switch (md->type) {
case eModifierType_Softbody:
BKE_object_copy_softbody(ob_dst, ob_src, 0);
break;
case eModifierType_Skin:
/* ensure skin-node customdata exists */
BKE_mesh_ensure_skin_customdata(ob_dst->data);
break;
}
nmd = BKE_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
if (md->type == eModifierType_Multires) {
/* Has to be done after mod creation, but *before* we actually copy its settings! */
multiresModifier_sync_levels_ex(
ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
}
BKE_modifier_copydata(md, nmd);
BLI_addtail(&ob_dst->modifiers, nmd);
BKE_modifier_unique_name(&ob_dst->modifiers, nmd);
return true;
}
bool BKE_object_link_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *md)
{
GpencilModifierData *nmd = NULL;
nmd = BKE_gpencil_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
mti->copyData(md, nmd);
BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd);
return true;
}
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
{
BKE_object_free_modifiers(ob_dst, 0);
@@ -702,54 +756,14 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
/* No grease pencil modifiers. */
if ((ob_src->type != OB_GPENCIL) && (ob_dst->type != OB_GPENCIL)) {
LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
ModifierData *nmd = NULL;
if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
continue;
}
if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
continue;
}
switch (md->type) {
case eModifierType_Softbody:
BKE_object_copy_softbody(ob_dst, ob_src, 0);
break;
case eModifierType_Skin:
/* ensure skin-node customdata exists */
BKE_mesh_ensure_skin_customdata(ob_dst->data);
break;
}
nmd = BKE_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
if (md->type == eModifierType_Multires) {
/* Has to be done after mod creation, but *before* we actually copy its settings! */
multiresModifier_sync_levels_ex(
ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
}
BKE_modifier_copydata(md, nmd);
BLI_addtail(&ob_dst->modifiers, nmd);
BKE_modifier_unique_name(&ob_dst->modifiers, nmd);
BKE_object_link_modifier(ob_dst, ob_src, md);
}
}
/* Copy grease pencil modifiers. */
if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) {
LISTBASE_FOREACH (GpencilModifierData *, md, &ob_src->greasepencil_modifiers) {
GpencilModifierData *nmd = NULL;
nmd = BKE_gpencil_modifier_new(md->type);
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
mti->copyData(md, nmd);
BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd);
BKE_object_link_gpencil_modifier(ob_dst, md);
}
}

View File

@@ -234,6 +234,19 @@ void BKE_shaderfx_copydata(ShaderFxData *fx, ShaderFxData *target)
BKE_shaderfx_copydata_ex(fx, target, 0);
}
void BKE_shaderfx_copy(ListBase *dst, const ListBase *src)
{
ShaderFxData *fx;
ShaderFxData *srcfx;
BLI_listbase_clear(dst);
BLI_duplicatelist(dst, src);
for (srcfx = src->first, fx = dst->first; srcfx && fx; srcfx = srcfx->next, fx = fx->next) {
BKE_shaderfx_copydata(srcfx, fx);
}
}
ShaderFxData *BKE_shaderfx_findby_type(Object *ob, ShaderFxType type)
{
ShaderFxData *fx = ob->shader_fx.first;

View File

@@ -3413,7 +3413,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
case SPACE_OUTLINER: {
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
space_outliner->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_UNUSED_5 |
space_outliner->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_NO_ROW_CHILDREN |
SO_FILTER_UNUSED_12);
space_outliner->storeflag &= ~(SO_TREESTORE_UNUSED_1);
break;

View File

@@ -517,5 +517,17 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
if (space->spacetype == SPACE_OUTLINER) {
SpaceOutliner *space_outliner = (SpaceOutliner *)space;
space_outliner->flag |= SO_MODE_COLUMN;
}
}
}
}
}
}

View File

@@ -217,6 +217,15 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
btheme->tui.transparent_checker_size = U_theme_default.tui.transparent_checker_size;
}
FROM_DEFAULT_V4_UCHAR(collection_color[0].color);
FROM_DEFAULT_V4_UCHAR(collection_color[1].color);
FROM_DEFAULT_V4_UCHAR(collection_color[2].color);
FROM_DEFAULT_V4_UCHAR(collection_color[3].color);
FROM_DEFAULT_V4_UCHAR(collection_color[4].color);
FROM_DEFAULT_V4_UCHAR(collection_color[5].color);
FROM_DEFAULT_V4_UCHAR(collection_color[6].color);
FROM_DEFAULT_V4_UCHAR(collection_color[7].color);
/**
* Versioning code until next subversion bump goes here.
*

View File

@@ -1971,7 +1971,7 @@ static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UN
/* call the menu, which will call this operator again, hence the canceled */
pup = UI_popup_menu_begin(C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type");
uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type", false);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;

View File

@@ -479,7 +479,7 @@ static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, const wmEve
/* call the menu, which will call this operator again, hence the canceled */
pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, "ANIM_OT_keying_set_active_set", "type");
uiItemsEnumO(layout, "ANIM_OT_keying_set_active_set", "type", false);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;

View File

@@ -5922,7 +5922,7 @@ static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
if (nu->type == CU_NURBS) {
pup = UI_popup_menu_begin(C, IFACE_("Direction"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, op->type->idname, "direction");
uiItemsEnumO(layout, op->type->idname, "direction", false);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}

View File

@@ -1403,7 +1403,7 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven
/* call the menu, which will call this operator again, hence the canceled */
pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer", false);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;

View File

@@ -26,8 +26,11 @@
extern "C" {
#endif
struct bContext;
struct SpaceProperties;
void ED_buttons_set_context(const struct bContext *C, PointerRNA *ptr, const short context);
int ED_buttons_tabs_list(struct SpaceProperties *sbuts, int *context_tabs_array);
#ifdef __cplusplus

View File

@@ -329,6 +329,11 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain,
struct Object *ob,
struct bConstraint *con);
bool ED_object_constraint_move_to_index(struct ReportList *reports,
struct Object *ob,
struct bConstraint *con,
const int index);
/* object_modes.c */
bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
bool ED_object_mode_compat_set(struct bContext *C,

View File

@@ -320,7 +320,7 @@ DEF_ICON_OBJECT(OUTLINER_OB_GROUP_INSTANCE)
DEF_ICON_OBJECT(OUTLINER_OB_GREASEPENCIL)
DEF_ICON_OBJECT(OUTLINER_OB_LIGHTPROBE)
DEF_ICON_OBJECT(OUTLINER_OB_IMAGE)
DEF_ICON_BLANK(321)
DEF_ICON(OUTLINER_COLLECTION)
DEF_ICON(RESTRICT_COLOR_OFF)
DEF_ICON(RESTRICT_COLOR_ON)
DEF_ICON(HIDE_ON)
@@ -980,6 +980,15 @@ DEF_ICON_VECTOR(COLORSET_18_VEC)
DEF_ICON_VECTOR(COLORSET_19_VEC)
DEF_ICON_VECTOR(COLORSET_20_VEC)
DEF_ICON_VECTOR(COLLECTION_COLOR_01)
DEF_ICON_VECTOR(COLLECTION_COLOR_02)
DEF_ICON_VECTOR(COLLECTION_COLOR_03)
DEF_ICON_VECTOR(COLLECTION_COLOR_04)
DEF_ICON_VECTOR(COLLECTION_COLOR_05)
DEF_ICON_VECTOR(COLLECTION_COLOR_06)
DEF_ICON_VECTOR(COLLECTION_COLOR_07)
DEF_ICON_VECTOR(COLLECTION_COLOR_08)
/* Events */
DEF_ICON_COLOR(EVENT_A)
DEF_ICON_COLOR(EVENT_B)

View File

@@ -2202,7 +2202,10 @@ void uiItemEnumO_string(uiLayout *layout,
const char *opname,
const char *propname,
const char *value);
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname);
void uiItemsEnumO(uiLayout *layout,
const char *opname,
const char *propname,
const bool icon_only);
void uiItemBooleanO(uiLayout *layout,
const char *name,
int icon,

View File

@@ -32,6 +32,7 @@ struct PointerRNA;
struct PreviewImage;
struct Scene;
struct bContext;
struct Collection;
enum eIconSizes;
@@ -106,6 +107,7 @@ struct PreviewImage *UI_icon_to_preview(int icon_id);
int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, const bool big);
int UI_idcode_icon_get(const int idcode);
int UI_library_icon_get(const struct ID *id);
int UI_collection_color_icon_get(const struct Collection *collection);
#ifdef __cplusplus
}

View File

@@ -383,13 +383,27 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
}
}
/* Keep aligned buttons in the same column. */
if (bt->alignnr && bt->next) {
int width = 0;
for (col_bt = bt; col_bt->rect.xmin < col_bt->next->rect.xmin; col_bt = col_bt->next) {
width += BLI_rctf_size_x(&col_bt->rect);
}
if (width > i) {
i = width;
}
bt = col_bt;
}
if (bt->next && bt->rect.xmin < bt->next->rect.xmin) {
/* End of this column, and it's not the last one. */
for (col_bt = init_col_bt; col_bt->prev != bt; col_bt = col_bt->next) {
col_bt->rect.xmin = x1addval;
col_bt->rect.xmax = x1addval + i + block->bounds;
if (!col_bt->alignnr) {
col_bt->rect.xmin = x1addval;
col_bt->rect.xmax = x1addval + i + block->bounds;
ui_but_update(col_bt); /* clips text again */
ui_but_update(col_bt); /* clips text again */
}
}
/* And we prepare next column. */
@@ -401,8 +415,10 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
/* Last column. */
for (col_bt = init_col_bt; col_bt; col_bt = col_bt->next) {
col_bt->rect.xmin = x1addval;
col_bt->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
if (!col_bt->alignnr) {
col_bt->rect.xmin = x1addval;
col_bt->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
}
ui_but_update(col_bt); /* clips text again */
}

View File

@@ -40,6 +40,7 @@
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_gpencil_types.h"
@@ -460,6 +461,33 @@ DEF_ICON_VECTOR_COLORSET_DRAW_NTH(20, 19)
# undef DEF_ICON_VECTOR_COLORSET_DRAW_NTH
static void vicon_collection_color_draw(
short color, int x, int y, int UNUSED(w), int UNUSED(h), float UNUSED(alpha))
{
bTheme *btheme = UI_GetTheme();
const ThemeCollectionColor *collection_color = &btheme->collection_color[color - 1];
UI_icon_draw_ex(
x, y, ICON_OUTLINER_COLLECTION, U.inv_dpi_fac, 1.0f, 0.0f, collection_color->color, true);
}
# define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \
static void vicon_collection_color_draw_##index(int x, int y, int w, int h, float alpha) \
{ \
vicon_collection_color_draw(color, x, y, w, h, alpha); \
}
DEF_ICON_COLLECTION_COLOR_DRAW(01, COLLECTION_COLOR_01);
DEF_ICON_COLLECTION_COLOR_DRAW(02, COLLECTION_COLOR_02);
DEF_ICON_COLLECTION_COLOR_DRAW(03, COLLECTION_COLOR_03);
DEF_ICON_COLLECTION_COLOR_DRAW(04, COLLECTION_COLOR_04);
DEF_ICON_COLLECTION_COLOR_DRAW(05, COLLECTION_COLOR_05);
DEF_ICON_COLLECTION_COLOR_DRAW(06, COLLECTION_COLOR_06);
DEF_ICON_COLLECTION_COLOR_DRAW(07, COLLECTION_COLOR_07);
DEF_ICON_COLLECTION_COLOR_DRAW(08, COLLECTION_COLOR_08);
# undef DEF_ICON_COLLECTION_COLOR_DRAW
/* Dynamically render icon instead of rendering a plain color to a texture/buffer
* This is not strictly a "vicon", as it needs access to icon->obj to get the color info,
* but it works in a very similar way.
@@ -985,6 +1013,15 @@ static void init_internal_icons(void)
def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18);
def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19);
def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20);
def_internal_vicon(ICON_COLLECTION_COLOR_01, vicon_collection_color_draw_01);
def_internal_vicon(ICON_COLLECTION_COLOR_02, vicon_collection_color_draw_02);
def_internal_vicon(ICON_COLLECTION_COLOR_03, vicon_collection_color_draw_03);
def_internal_vicon(ICON_COLLECTION_COLOR_04, vicon_collection_color_draw_04);
def_internal_vicon(ICON_COLLECTION_COLOR_05, vicon_collection_color_draw_05);
def_internal_vicon(ICON_COLLECTION_COLOR_06, vicon_collection_color_draw_06);
def_internal_vicon(ICON_COLLECTION_COLOR_07, vicon_collection_color_draw_07);
def_internal_vicon(ICON_COLLECTION_COLOR_08, vicon_collection_color_draw_08);
}
# endif /* WITH_HEADLESS */
@@ -2148,6 +2185,9 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big)
case ID_SCR:
iconid = ui_id_screen_get_icon(C, id);
break;
case ID_GR:
iconid = UI_collection_color_icon_get((Collection *)id);
break;
default:
break;
}
@@ -2309,6 +2349,17 @@ int UI_idcode_icon_get(const int idcode)
}
}
int UI_collection_color_icon_get(const Collection *collection)
{
int icon = ICON_OUTLINER_COLLECTION;
if (collection->color != COLLECTION_COLOR_NONE) {
icon = ICON_COLLECTION_COLOR_01 + (collection->color - 1);
}
return icon;
}
/* draws icon with dpi scale factor */
void UI_icon_draw(float x, float y, int icon_id)
{

View File

@@ -1208,6 +1208,10 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout,
but->flag |= UI_SELECT_DRAW;
}
if (flag & UI_ITEM_R_ICON_ONLY) {
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
}
if (layout->redalert) {
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
@@ -1428,6 +1432,13 @@ void uiItemsFullEnumO_items(uiLayout *layout,
if (radial) {
target = uiLayoutRadial(layout);
}
else if (layout->item.type == ITEM_LAYOUT_ROW && flag & UI_ITEM_R_ICON_ONLY) {
target = layout;
/* Add a blank button to the beginning of the row. */
uiDefIconBut(
block, UI_BTYPE_LABEL, 0, ICON_BLANK1, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
}
else {
split = uiLayoutSplit(layout, 0.0f, false);
target = uiLayoutColumn(split, layout->align);
@@ -1475,7 +1486,14 @@ void uiItemsFullEnumO_items(uiLayout *layout,
}
RNA_property_enum_set(&tptr, prop, item->value);
uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag, NULL);
uiItemFullO_ptr(target,
ot,
(flag & UI_ITEM_R_ICON_ONLY) ? NULL : item->name,
item->icon,
tptr.data,
context,
flag,
NULL);
ui_but_tip_from_enum_item(block->buttons.last, item);
}
@@ -1599,9 +1617,14 @@ void uiItemsFullEnumO(uiLayout *layout,
}
}
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname, const bool icon_only)
{
uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
uiItemsFullEnumO(layout,
opname,
propname,
NULL,
layout->root->opcontext,
icon_only ? UI_ITEM_R_ICON_ONLY : 0);
}
/* for use in cases where we have */
@@ -3372,7 +3395,7 @@ static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, vo
MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
uiLayoutSetOperatorContext(layout, lvl->opcontext);
uiItemsEnumO(layout, lvl->opname, lvl->propname);
uiItemsEnumO(layout, lvl->opname, lvl->propname, false);
layout->root->block->flag |= UI_BLOCK_IS_FLIP;
@@ -3718,18 +3741,18 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
}
}
static void ui_litem_layout_column(uiLayout *litem, bool is_box)
static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu)
{
int itemh, x, y;
int itemw, itemh, x, y;
x = litem->x;
y = litem->y;
LISTBASE_FOREACH (uiItem *, item, &litem->items) {
ui_item_size(item, NULL, &itemh);
ui_item_size(item, &itemw, &itemh);
y -= itemh;
ui_item_position(item, x, y, litem->w, itemh);
ui_item_position(item, x, y, is_menu ? itemw : litem->w, itemh);
if (item->next && (!is_box || item != litem->items.first)) {
y -= litem->space;
@@ -3890,8 +3913,11 @@ static void ui_litem_layout_root(uiLayout *litem)
else if (litem->root->type == UI_LAYOUT_PIEMENU) {
ui_litem_layout_root_radial(litem);
}
else if (litem->root->type == UI_LAYOUT_MENU) {
ui_litem_layout_column(litem, false, true);
}
else {
ui_litem_layout_column(litem, false);
ui_litem_layout_column(litem, false, false);
}
}
@@ -3935,7 +3961,7 @@ static void ui_litem_layout_box(uiLayout *litem)
litem->h -= 2 * boxspace;
}
ui_litem_layout_column(litem, true);
ui_litem_layout_column(litem, true, false);
litem->x -= boxspace;
litem->y -= boxspace;
@@ -5196,7 +5222,7 @@ static void ui_item_layout(uiItem *item)
switch (litem->item.type) {
case ITEM_LAYOUT_COLUMN:
ui_litem_layout_column(litem, false);
ui_litem_layout_column(litem, false, false);
break;
case ITEM_LAYOUT_COLUMN_FLOW:
ui_litem_layout_column_flow(litem);

View File

@@ -261,7 +261,7 @@ int UI_pie_menu_invoke_from_operator_enum(struct bContext *C,
layout = UI_pie_menu_layout(pie);
layout = uiLayoutRadial(layout);
uiItemsEnumO(layout, opname, propname);
uiItemsEnumO(layout, opname, propname, false);
UI_pie_menu_end(C, pie);

View File

@@ -2376,7 +2376,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
rect->xmin += 0.3f * U.widget_unit;
}
}
else if (ui_block_is_menu(but->block)) {
else if (ui_block_is_menu(but->block) && but->alignnr == 0) {
rect->xmin += 0.2f * U.widget_unit;
}

View File

@@ -50,6 +50,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "UI_interface_icons.h"
#include "object_intern.h"
/********************* 3d view operators ***********************/
@@ -94,7 +96,7 @@ static const EnumPropertyItem *collection_object_active_itemf(bContext *C,
collection = NULL;
while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
item_tmp.identifier = item_tmp.name = collection->id.name + 2;
/* item_tmp.icon = ICON_ARMATURE_DATA; */
item_tmp.icon = UI_collection_color_icon_get(collection);
item_tmp.value = i;
RNA_enum_item_add(&item, &totitem, &item_tmp);
i++;

View File

@@ -1421,6 +1421,24 @@ void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstr
DEG_relations_tag_update(bmain);
}
/* TODO (Nathan): Use the reports? */
bool ED_object_constraint_move_to_index(ReportList *reports,
Object *ob,
bConstraint *con,
const int index)
{
BLI_assert(con != NULL);
BLI_assert(index >= 0);
ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
int current_index = BLI_findindex(conlist, con);
BLI_assert(current_index >= 0);
BLI_listbase_link_move(conlist, con, index - current_index);
return true;
}
/** \} */
/* ------------------------------------------------------------------- */
@@ -1613,11 +1631,7 @@ static int constraint_move_to_index_exec(bContext *C, wmOperator *op)
}
if (con) {
ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
int current_index = BLI_findindex(conlist, con);
BLI_assert(current_index >= 0);
BLI_listbase_link_move(conlist, con, new_index - current_index);
ED_object_constraint_move_to_index(op->reports, ob, con, new_index);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);

View File

@@ -100,6 +100,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "UI_interface_icons.h"
#include "CLG_log.h"
/* for menu/popup icons etc etc*/
@@ -1761,7 +1763,7 @@ static void move_to_collection_menus_free(MoveToCollectionData **menu)
*menu = NULL;
}
static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v)
static void move_to_collection_menu_create(bContext *C, uiLayout *layout, void *menu_v)
{
MoveToCollectionData *menu = menu_v;
const char *name = BKE_collection_ui_name_get(menu->collection);
@@ -1777,7 +1779,11 @@ static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout
uiItemS(layout);
uiItemIntO(layout, name, ICON_SCENE_DATA, menu->ot->idname, "collection_index", menu->index);
Scene *scene = CTX_data_scene(C);
const int icon = (menu->collection == scene->master_collection) ?
ICON_SCENE_DATA :
UI_collection_color_icon_get(menu->collection);
uiItemIntO(layout, name, icon, menu->ot->idname, "collection_index", menu->index);
for (MoveToCollectionData *submenu = menu->submenus.first; submenu != NULL;
submenu = submenu->next) {
@@ -1787,17 +1793,18 @@ static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout
static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu)
{
const int icon = UI_collection_color_icon_get(menu->collection);
if (BLI_listbase_is_empty(&menu->submenus)) {
uiItemIntO(layout,
menu->collection->id.name + 2,
ICON_NONE,
icon,
menu->ot->idname,
"collection_index",
menu->index);
}
else {
uiItemMenuF(
layout, menu->collection->id.name + 2, ICON_NONE, move_to_collection_menu_create, menu);
uiItemMenuF(layout, menu->collection->id.name + 2, icon, move_to_collection_menu_create, menu);
}
}

View File

@@ -535,11 +535,11 @@ static bool buttons_context_linestyle_pinnable(const bContext *C, ViewLayer *vie
}
#endif
static bool buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
static bool buttons_context_path(
const bContext *C, SpaceProperties *sbuts, ButsContextPath *path, int mainb, int flag)
{
/* Note we don't use CTX_data here, instead we get it from the window.
* Otherwise there is a loop reading the context that we are setting. */
SpaceProperties *sbuts = CTX_wm_space_properties(C);
wmWindow *window = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(window);
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
@@ -685,14 +685,14 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
path = sbuts->path;
/* Set scene path. */
buttons_context_path(C, path, BCONTEXT_SCENE, pflag);
buttons_context_path(C, sbuts, path, BCONTEXT_SCENE, pflag);
buttons_texture_context_compute(C, sbuts);
/* for each context, see if we can compute a valid path to it, if
* this is the case, we know we have to display the button */
for (a = 0; a < BCONTEXT_TOT; a++) {
if (buttons_context_path(C, path, a, pflag)) {
if (buttons_context_path(C, sbuts, path, a, pflag)) {
flag |= (1 << a);
/* setting icon for data context */
@@ -738,7 +738,7 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
}
}
buttons_context_path(C, path, sbuts->mainb, pflag);
buttons_context_path(C, sbuts, path, sbuts->mainb, pflag);
if (!(flag & (1 << sbuts->mainb))) {
if (flag & (1 << BCONTEXT_OBJECT)) {
@@ -759,6 +759,38 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
sbuts->pathflag = flag;
}
static bool is_pointer_in_path(ButsContextPath *path, PointerRNA *ptr)
{
for (int i = 0; i < path->len; ++i) {
if (ptr->owner_id == path->ptr[i].owner_id) {
return true;
}
}
return false;
}
void ED_buttons_set_context(const bContext *C, PointerRNA *ptr, const short context)
{
bScreen *screen = CTX_wm_screen(C);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
/* Only update for properties editors that are visible */
SpaceLink *sl = area->spacedata.first;
if (sl->spacetype == SPACE_PROPERTIES) {
SpaceProperties *sbuts = (SpaceProperties *)sl;
ButsContextPath path;
if (buttons_context_path(C, sbuts, &path, context, 0)) {
if (is_pointer_in_path(&path, ptr)) {
sbuts->mainbuser = context;
sbuts->mainb = sbuts->mainbuser;
}
}
}
}
}
/************************* Context Callback ************************/
const char *buttons_context_dir[] = {

View File

@@ -256,7 +256,7 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
layout = UI_popup_menu_layout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
uiItemsEnumO(layout, "FILE_OT_unpack_all", "method");
uiItemsEnumO(layout, "FILE_OT_unpack_all", "method", false);
UI_popup_menu_end(C, pup);

View File

@@ -183,60 +183,35 @@ static bool outliner_view_layer_collections_editor_poll(bContext *C)
/** \name New Collection
* \{ */
struct CollectionNewData {
bool error;
Collection *collection;
};
typedef enum NewCollectionType {
COLLECTION_NEW_EMPTY,
COLLECTION_NEW_FROM_SELECTION,
COLLECTION_NEW_FROM_SELECTION_LINKED,
} NewCollectionType;
static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
static Collection *find_parent_collection(TreeElement *te)
{
struct CollectionNewData *data = customdata;
Collection *collection = outliner_collection_from_tree_element(te);
if (!collection) {
return TRAVERSE_SKIP_CHILDS;
while (te) {
te = te->parent;
if (outliner_is_collection_tree_element(te)) {
return outliner_collection_from_tree_element(te);
}
}
if (data->collection != NULL) {
data->error = true;
return TRAVERSE_BREAK;
}
data->collection = collection;
return TRAVERSE_CONTINUE;
return NULL;
}
static int collection_new_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
ARegion *region = CTX_wm_region(C);
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Collection *collection;
const short type = RNA_enum_get(op->ptr, "type");
struct CollectionNewData data = {
.error = false,
.collection = NULL,
};
if (RNA_boolean_get(op->ptr, "nested")) {
outliner_build_tree(bmain, scene, view_layer, space_outliner, region);
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
TSE_SELECTED,
collection_find_selected_to_add,
&data);
if (data.error) {
BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
return OPERATOR_CANCELLED;
}
}
if (data.collection == NULL || ID_IS_LINKED(data.collection)) {
data.collection = scene->master_collection;
/* Make new collection a child of the active collection */
collection = CTX_data_layer_collection(C)->collection;
if (ID_IS_LINKED(collection)) {
collection = scene->master_collection;
}
if (ID_IS_LINKED(scene)) {
@@ -244,9 +219,35 @@ static int collection_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
BKE_collection_add(bmain, data.collection, NULL);
Collection *collection_new = BKE_collection_add(bmain, collection, NULL);
DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE);
if (type != COLLECTION_NEW_EMPTY) {
/* Move selected objects into new collection */
struct IDsSelectedData data = {{NULL}};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
TSE_SELECTED,
outliner_find_selected_objects,
&data);
LISTBASE_FOREACH (LinkData *, link, &data.selected_array) {
TreeElement *te = (TreeElement *)link->data;
TreeStoreElem *tselem = TREESTORE(te);
Collection *parent = find_parent_collection(te);
Object *ob = (Object *)tselem->id;
if (type == COLLECTION_NEW_FROM_SELECTION) {
BKE_collection_object_move(bmain, scene, collection_new, parent, ob);
}
else {
BKE_collection_object_add(bmain, collection_new, ob);
}
}
BLI_freelistN(&data.selected_array);
}
DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
outliner_cleanup_tree(space_outliner);
@@ -256,10 +257,29 @@ static int collection_new_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_collection_new(wmOperatorType *ot)
{
static EnumPropertyItem type_items[] = {
{COLLECTION_NEW_EMPTY,
"EMPTY",
0,
"Empty",
"Create a new collection inside the active collection"},
{COLLECTION_NEW_FROM_SELECTION,
"SELECTION",
0,
"Move Objects",
"Move the selected objects to a new collection"},
{COLLECTION_NEW_FROM_SELECTION_LINKED,
"SELECTION_LINKED",
0,
"Link Objects",
"Link the selected objects to a new collection"},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "New Collection";
ot->idname = "OUTLINER_OT_collection_new";
ot->description = "Add a new collection inside selected collection";
ot->description = "Create a new collection";
/* api callbacks */
ot->exec = collection_new_exec;
@@ -269,9 +289,7 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop = RNA_def_boolean(
ot->srna, "nested", true, "Nested", "Add as child of selected collection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->prop = RNA_def_enum(ot->srna, "type", type_items, COLLECTION_NEW_FROM_SELECTION, "Type", "");
}
/** \} */
@@ -563,7 +581,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
/* Can happen when calling from a key binding. */
if (te == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active collection");
BKE_reportf(op->reports, RPT_WARNING, "No active collection");
return OPERATOR_CANCELLED;
}
@@ -1529,3 +1547,66 @@ void OUTLINER_OT_unhide_all(wmOperatorType *ot)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Collection Color Tags
* \{ */
static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
const short color_tag = RNA_enum_get(op->ptr, "color");
struct IDsSelectedData selected = {
.selected_array = {NULL, NULL},
};
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
TSE_SELECTED,
outliner_find_selected_collections,
&selected);
LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) {
TreeElement *te_selected = (TreeElement *)link->data;
Collection *collection = outliner_collection_from_tree_element(te_selected);
if (collection == scene->master_collection) {
continue;
}
if (ID_IS_LINKED(collection)) {
BKE_report(op->reports, RPT_WARNING, "Can't add a color tag to a linked collection");
continue;
}
collection->color = color_tag;
};
BLI_freelistN(&selected.selected_array);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
return OPERATOR_FINISHED;
}
void OUTLINER_OT_collection_color_tag_set(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Set Color Tag";
ot->idname = "OUTLINER_OT_collection_color_tag_set";
ot->description = "Set a color tag for the selected collections";
/* api callbacks */
ot->exec = outliner_color_tag_set_exec;
ot->poll = ED_outliner_collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_enum(
ot->srna, "color", rna_enum_collection_color_items, COLLECTION_COLOR_NONE, "Color Tag", "");
}
/** \} */

View File

@@ -26,7 +26,9 @@
#include "MEM_guardedalloc.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
@@ -36,6 +38,7 @@
#include "BLT_translation.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -44,6 +47,7 @@
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_shader_fx.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -65,6 +69,42 @@
#include "outliner_intern.h"
static Collection *collection_parent_from_ID(ID *id);
/* ******************** Drop Data Functions *********************** */
typedef struct OutlinerDropData {
Object *ob_parent;
bPoseChannel *bone_parent;
TreeStoreElem *drag_tselem;
void *drag_directdata;
int drag_index;
int drop_action;
TreeElement *drop_te;
TreeElementInsertType insert_type;
} OutlinerDropData;
/* */
static void outliner_drop_data_init(wmDrag *drag,
Object *ob,
bPoseChannel *pchan,
TreeElement *te,
TreeStoreElem *tselem,
void *directdata)
{
OutlinerDropData *drop_data = MEM_callocN(sizeof(OutlinerDropData), "outliner drop data");
drop_data->ob_parent = ob;
drop_data->bone_parent = pchan;
drop_data->drag_tselem = tselem;
drop_data->drag_directdata = directdata;
drop_data->drag_index = te->index;
drag->poin = drop_data;
drag->flags |= WM_DRAG_FREE_DATA;
}
/* ******************** Drop Target Find *********************** */
static TreeElement *outliner_dropzone_element(TreeElement *te,
@@ -146,7 +186,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
const float margin = UI_UNIT_Y * (1.0f / 4);
if (view_mval[1] < (te_hovered->ys + margin)) {
if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner)) {
if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner) &&
!BLI_listbase_is_empty(&te_hovered->subtree)) {
/* inserting after a open item means we insert into it, but as first child */
if (BLI_listbase_is_empty(&te_hovered->subtree)) {
*r_insert_type = TE_INSERT_INTO;
@@ -212,6 +253,11 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C,
return NULL;
}
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
if (space_outliner->sort_method != SO_SORT_FREE) {
*r_insert_type = TE_INSERT_INTO;
}
if (collection_te != te) {
*r_insert_type = TE_INSERT_INTO;
}
@@ -224,10 +270,77 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C,
return collection_te;
}
static Object *outliner_object_from_tree_element_and_parents(TreeElement *te, TreeElement **r_te)
{
TreeStoreElem *tselem;
while (te != NULL) {
tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
*r_te = te;
return (Object *)tselem->id;
}
te = te->parent;
}
return NULL;
}
static bPoseChannel *outliner_bone_from_tree_element_and_parents(TreeElement *te,
TreeElement **r_te)
{
TreeStoreElem *tselem;
while (te != NULL) {
tselem = TREESTORE(te);
if (tselem->type == TSE_POSE_CHANNEL) {
*r_te = te;
return (bPoseChannel *)te->directdata;
}
te = te->parent;
}
return NULL;
}
static int outliner_get_insert_index(TreeElement *drag_te,
TreeElement *drop_te,
TreeElementInsertType insert_type,
ListBase *listbase)
{
/* Find the element to insert after. NULL is the start of the list. */
if (drag_te->index < drop_te->index) {
if (insert_type == TE_INSERT_BEFORE) {
drop_te = drop_te->prev;
}
}
else {
if (insert_type == TE_INSERT_AFTER) {
drop_te = drop_te->next;
}
}
if (drop_te == NULL) {
return 0;
}
return BLI_findindex(listbase, drop_te->directdata);
}
/* ******************** Parent Drop Operator *********************** */
static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
static bool parent_drop_allowed(bContext *C,
const wmEvent *event,
TreeElement *te,
Object *potential_child)
{
ARegion *region = CTX_wm_region(C);
float view_mval[2];
UI_view2d_region_to_view(
&region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
/* Check if over name. */
if ((view_mval[0] < te->xs + UI_UNIT_X) || (view_mval[0] > te->xend)) {
return false;
}
TreeStoreElem *tselem = TREESTORE(te);
if (te->idcode != ID_OB || tselem->type != 0) {
return false;
@@ -262,26 +375,14 @@ static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
return true;
}
static bool allow_parenting_without_modifier_key(SpaceOutliner *space_outliner)
{
switch (space_outliner->outlinevis) {
case SO_VIEW_LAYER:
return space_outliner->filter & SO_FILTER_NO_COLLECTION;
case SO_SCENES:
return true;
default:
return false;
}
}
static bool parent_drop_poll(bContext *C,
wmDrag *drag,
const wmEvent *event,
const char **UNUSED(r_tooltip))
const char **r_tooltip)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
bool changed = outliner_flag_set(&space_outliner->tree, TSE_DRAG_ANY, false);
bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
if (changed) {
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
}
@@ -291,24 +392,39 @@ static bool parent_drop_poll(bContext *C,
return false;
}
if (!allow_parenting_without_modifier_key(space_outliner)) {
if (!event->shift) {
return false;
}
}
TreeElement *te = outliner_drop_find(C, event);
TreeElementInsertType insert_type;
TreeElement *te = outliner_drop_insert_find(C, event, &insert_type);
if (!te) {
return false;
}
TreeStoreElem *tselem = TREESTORE(te);
if (parent_drop_allowed(te, potential_child)) {
TREESTORE(te)->flag |= TSE_DRAG_INTO;
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
return true;
if (space_outliner->sort_method != SO_SORT_FREE || space_outliner->outlinevis != SO_VIEW_LAYER) {
insert_type = TE_INSERT_INTO;
}
return false;
if (!parent_drop_allowed(C, event, te, potential_child)) {
return false;
}
switch (insert_type) {
case TE_INSERT_BEFORE:
tselem->flag |= TSE_DRAG_BEFORE;
*r_tooltip = TIP_("Reorder object");
break;
case TE_INSERT_AFTER:
tselem->flag |= TSE_DRAG_AFTER;
*r_tooltip = TIP_("Reorder object");
break;
case TE_INSERT_INTO:
tselem->flag |= TSE_DRAG_INTO;
break;
}
TREESTORE(te)->flag |= TSE_DRAG_INTO;
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
return true;
}
static void parent_drop_set_parents(bContext *C,
@@ -364,9 +480,50 @@ static void parent_drop_set_parents(bContext *C,
}
}
static void parent_drop_move_objects(bContext *C, wmDragID *drag, TreeElement *te)
{
Main *bmain = CTX_data_main(C);
Scene *scene = (Scene *)outliner_search_back(te, ID_SCE);
if (scene == NULL) {
scene = CTX_data_scene(C);
}
Object *ob_drop = (Object *)TREESTORE(te)->id;
Collection *collection_to = collection_parent_from_ID(&ob_drop->id);
while (te) {
te = te->parent;
if (outliner_is_collection_tree_element(te)) {
collection_to = outliner_collection_from_tree_element(te);
break;
}
}
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;
/* Do nothing to linked data */
if (ID_IS_LINKED(object)) {
continue;
}
Collection *from = collection_parent_from_ID(drag_id->from_parent);
BKE_collection_object_move(bmain, scene, collection_to, from, object);
BKE_collection_object_move_after(bmain, collection_to, ob_drop, object);
}
}
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);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
}
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
TreeElement *te = outliner_drop_find(C, event);
TreeElementInsertType insert_type;
TreeElement *te = outliner_drop_insert_find(C, event, &insert_type);
TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
if (!(te && te->idcode == ID_OB && tselem->type == 0)) {
@@ -390,7 +547,17 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ListBase *lb = event->customdata;
wmDrag *drag = lb->first;
parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
if (space_outliner->sort_method != SO_SORT_FREE || space_outliner->outlinevis != SO_VIEW_LAYER) {
insert_type = TE_INSERT_INTO;
}
if (insert_type == TE_INSERT_INTO) {
parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
}
else {
parent_drop_move_objects(C, drag->ids.first, te);
}
return OPERATOR_FINISHED;
}
@@ -418,14 +585,6 @@ static bool parent_clear_poll(bContext *C,
const wmEvent *event,
const char **UNUSED(r_tooltip))
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
if (!allow_parenting_without_modifier_key(space_outliner)) {
if (!event->shift) {
return false;
}
}
Object *ob = (Object *)WM_drag_ID(drag, ID_OB);
if (!ob) {
return false;
@@ -616,6 +775,318 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
/* ******************** UI Stack Drop Operator *********************** */
/* A generic operator to allow drag and drop for modifiers, constraints,
* and shader effects which all share the same UI stack layout.
*
* The following operations are allowed:
* - Reordering within an object.
* - Copying a single modifier/constraint/effect to another object.
* - Copying (linking) an object's modifiers/constraints/effects to another. */
enum eUIStackDropAction {
UI_STACK_DROP_REORDER,
UI_STACK_DROP_COPY,
UI_STACK_DROP_LINK,
};
static bool uistack_drop_poll(bContext *C,
wmDrag *drag,
const wmEvent *event,
const char **r_tooltip)
{
OutlinerDropData *drop_data = drag->poin;
if (!drop_data) {
return false;
}
if (!ELEM(drop_data->drag_tselem->type,
TSE_MODIFIER,
TSE_MODIFIER_BASE,
TSE_CONSTRAINT,
TSE_CONSTRAINT_BASE,
TSE_EFFECT,
TSE_EFFECT_BASE)) {
return false;
}
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
ARegion *region = CTX_wm_region(C);
bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
if (!te_target) {
return false;
}
TreeStoreElem *tselem_target = TREESTORE(te_target);
if (drop_data->drag_tselem == tselem_target) {
return false;
}
TreeElement *object_te;
TreeElement *bone_te;
Object *ob = outliner_object_from_tree_element_and_parents(te_target, &object_te);
bPoseChannel *pchan = outliner_bone_from_tree_element_and_parents(te_target, &bone_te);
if (pchan) {
ob = NULL;
}
/* Drag a base for linking. */
if (ELEM(
drop_data->drag_tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE, TSE_EFFECT_BASE)) {
drop_data->insert_type = TE_INSERT_INTO;
drop_data->drop_action = UI_STACK_DROP_LINK;
if (pchan && pchan != drop_data->bone_parent) {
*r_tooltip = TIP_("Link all to bone");
drop_data->drop_te = bone_te;
tselem_target = TREESTORE(bone_te);
}
else if (ob && ob != drop_data->ob_parent) {
*r_tooltip = TIP_("Link all to object");
drop_data->drop_te = object_te;
tselem_target = TREESTORE(object_te);
}
else {
return false;
}
}
else if (ob || pchan) {
/* Drag a single item. */
if (pchan && pchan != drop_data->bone_parent) {
*r_tooltip = TIP_("Copy to bone");
drop_data->insert_type = TE_INSERT_INTO;
drop_data->drop_action = UI_STACK_DROP_COPY;
drop_data->drop_te = bone_te;
tselem_target = TREESTORE(bone_te);
}
else if (ob && ob != drop_data->ob_parent) {
*r_tooltip = TIP_("Copy to object");
drop_data->insert_type = TE_INSERT_INTO;
drop_data->drop_action = UI_STACK_DROP_COPY;
drop_data->drop_te = object_te;
tselem_target = TREESTORE(object_te);
}
else if (tselem_target->type == drop_data->drag_tselem->type) {
if (drop_data->insert_type == TE_INSERT_INTO) {
return false;
}
*r_tooltip = TIP_("Reorder");
drop_data->drop_action = UI_STACK_DROP_REORDER;
drop_data->drop_te = te_target;
}
else {
return false;
}
}
else {
return false;
}
switch (drop_data->insert_type) {
case TE_INSERT_BEFORE:
tselem_target->flag |= TSE_DRAG_BEFORE;
break;
case TE_INSERT_AFTER:
tselem_target->flag |= TSE_DRAG_AFTER;
break;
case TE_INSERT_INTO:
tselem_target->flag |= TSE_DRAG_INTO;
break;
}
if (changed) {
ED_region_tag_redraw_no_rebuild(region);
}
return true;
}
static void uistack_drop_link(bContext *C, OutlinerDropData *drop_data)
{
Main *bmain = CTX_data_main(C);
TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
Object *ob_dst = (Object *)tselem->id;
if (drop_data->drag_tselem->type == TSE_MODIFIER_BASE) {
BKE_object_link_modifiers(ob_dst, drop_data->ob_parent);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob_dst);
DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
}
else if (drop_data->drag_tselem->type == TSE_CONSTRAINT_BASE) {
ListBase *src;
if (drop_data->bone_parent) {
src = &drop_data->bone_parent->constraints;
}
else {
src = &drop_data->ob_parent->constraints;
}
ListBase *dst;
if (tselem->type == TSE_POSE_CHANNEL) {
bPoseChannel *pchan = (bPoseChannel *)drop_data->drop_te->directdata;
dst = &pchan->constraints;
}
else {
dst = &ob_dst->constraints;
}
BKE_constraints_copy(dst, src, true);
LISTBASE_FOREACH (bConstraint *, con, dst) {
ED_object_constraint_dependency_tag_update(bmain, ob_dst, con);
}
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, NULL);
}
else if (drop_data->drag_tselem->type == TSE_EFFECT_BASE) {
if (ob_dst->type != OB_GPENCIL) {
return;
}
BKE_shaderfx_copy(&ob_dst->shader_fx, &drop_data->ob_parent->shader_fx);
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob_dst);
}
}
static void uistack_drop_copy(bContext *C, OutlinerDropData *drop_data)
{
Main *bmain = CTX_data_main(C);
TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
Object *ob_dst = (Object *)tselem->id;
if (drop_data->drag_tselem->type == TSE_MODIFIER) {
if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
BKE_object_link_gpencil_modifier(ob_dst, drop_data->drag_directdata);
}
else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
BKE_object_link_modifier(ob_dst, drop_data->ob_parent, drop_data->drag_directdata);
}
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob_dst);
DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
}
else if (drop_data->drag_tselem->type == TSE_CONSTRAINT) {
if (tselem->type == TSE_POSE_CHANNEL) {
BKE_constraint_copy_for_pose(
ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata);
}
else {
BKE_constraint_copy_for_object(ob_dst, drop_data->drag_directdata);
}
ED_object_constraint_dependency_tag_update(bmain, ob_dst, drop_data->drag_directdata);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob_dst);
}
else if (drop_data->drag_tselem->type == TSE_EFFECT) {
if (ob_dst->type != OB_GPENCIL) {
return;
}
ShaderFxData *fx = drop_data->drag_directdata;
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
BKE_shaderfx_copydata(fx, nfx);
BLI_addtail(&ob_dst->shader_fx, nfx);
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob_dst);
}
}
static void uistack_drop_reorder(bContext *C, ReportList *reports, OutlinerDropData *drop_data)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeElement *drag_te = outliner_find_tree_element(&space_outliner->tree, drop_data->drag_tselem);
if (!drag_te) {
return;
}
TreeElement *drop_te = drop_data->drop_te;
TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
TreeElementInsertType insert_type = drop_data->insert_type;
Object *ob_dst = (Object *)tselem->id;
Object *ob = drop_data->ob_parent;
int index = 0;
if (drop_data->drag_tselem->type == TSE_MODIFIER) {
if (ob->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
index = outliner_get_insert_index(
drag_te, drop_te, insert_type, &ob->greasepencil_modifiers);
ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
}
else if (ob->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
else if (drop_data->drag_tselem->type == TSE_CONSTRAINT) {
if (drop_data->bone_parent) {
index = outliner_get_insert_index(
drag_te, drop_te, insert_type, &drop_data->bone_parent->constraints);
}
else {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints);
}
ED_object_constraint_move_to_index(reports, ob, drop_data->drag_directdata, index);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
}
else if (drop_data->drag_tselem->type == TSE_EFFECT) {
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx);
ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
}
}
static int uistack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (event->custom != EVT_DATA_DRAGDROP) {
return OPERATOR_CANCELLED;
}
ListBase *lb = event->customdata;
wmDrag *drag = lb->first;
OutlinerDropData *drop_data = drag->poin;
switch (drop_data->drop_action) {
case UI_STACK_DROP_LINK:
uistack_drop_link(C, drop_data);
break;
case UI_STACK_DROP_COPY:
uistack_drop_copy(C, drop_data);
break;
case UI_STACK_DROP_REORDER:
uistack_drop_reorder(C, op->reports, drop_data);
break;
}
return OPERATOR_FINISHED;
}
void OUTLINER_OT_uistack_drop(wmOperatorType *ot)
{
/* identifiers */
ot->name = "UI Stack Drop";
ot->description = "Copy or reorder modifiers, constraints, and effects";
ot->idname = "OUTLINER_OT_uistack_drop";
/* api callbacks */
ot->invoke = uistack_drop_invoke;
ot->poll = ED_operator_outliner_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
}
/* ******************** Collection Drop Operator *********************** */
typedef struct CollectionDrop {
@@ -730,22 +1201,12 @@ static bool collection_drop_poll(bContext *C,
case TE_INSERT_BEFORE:
tselem->flag |= TSE_DRAG_BEFORE;
changed = true;
if (te->prev && outliner_is_collection_tree_element(te->prev)) {
*r_tooltip = TIP_("Move between collections");
}
else {
*r_tooltip = TIP_("Move before collection");
}
*r_tooltip = TIP_("Reorder collection(s)");
break;
case TE_INSERT_AFTER:
tselem->flag |= TSE_DRAG_AFTER;
changed = true;
if (te->next && outliner_is_collection_tree_element(te->next)) {
*r_tooltip = TIP_("Move between collections");
}
else {
*r_tooltip = TIP_("Move after collection");
}
*r_tooltip = TIP_("Reorder collection(s)");
break;
case TE_INSERT_INTO:
tselem->flag |= TSE_DRAG_INTO;
@@ -882,7 +1343,8 @@ static int outliner_item_drag_drop_invoke(bContext *C,
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te);
TreeStoreElem *tselem = TREESTORE(te);
TreeElementIcon data = tree_element_get_icon(tselem, te);
if (!data.drag_id) {
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
@@ -893,6 +1355,9 @@ static int outliner_item_drag_drop_invoke(bContext *C,
if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
if (outliner_is_co_within_mode_column(space_outliner, view_mval)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
/* Scroll the view when dragging near edges, but not
* when the drag goes too far outside the region. */
@@ -907,13 +1372,25 @@ static int outliner_item_drag_drop_invoke(bContext *C,
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)) {
if (ELEM(tselem->type,
TSE_MODIFIER,
TSE_MODIFIER_BASE,
TSE_CONSTRAINT,
TSE_CONSTRAINT_BASE,
TSE_EFFECT,
TSE_EFFECT_BASE)) {
TreeElement *te_bone = NULL;
bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone);
outliner_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata);
}
else if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {
/* For collections and objects we cheat and drag all selected. */
/* Only drag element under mouse if it was not selected before. */
if ((TREESTORE(te)->flag & TSE_SELECTED) == 0) {
if ((tselem->flag & TSE_SELECTED) == 0) {
outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
TREESTORE(te)->flag |= TSE_SELECTED;
tselem->flag |= TSE_SELECTED;
}
/* Gather all selected elements. */
@@ -992,7 +1469,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
WM_drag_add_ID(drag, data.drag_id, data.drag_parent);
}
ED_outliner_select_sync_from_all_tag(C);
ED_outliner_select_sync_from_outliner(C, space_outliner);
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
@@ -1024,5 +1501,6 @@ void outliner_dropboxes(void)
WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL);
WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL);
WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL);
WM_dropbox_add(lb, "OUTLINER_OT_uistack_drop", uistack_drop_poll, NULL);
WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL);
}

View File

@@ -53,6 +53,7 @@
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -182,7 +183,7 @@ static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void *UNU
{
Bone *bone = (Bone *)poin;
if (CTX_wm_window(C)->eventstate->ctrl) {
if (CTX_wm_window(C)->eventstate->shift) {
restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
}
}
@@ -194,7 +195,7 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void
bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
if (CTX_wm_window(C)->eventstate->ctrl) {
if (CTX_wm_window(C)->eventstate->shift) {
restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
}
@@ -209,7 +210,7 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *UNUSED(poin), void
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
if (CTX_wm_window(C)->eventstate->ctrl) {
if (CTX_wm_window(C)->eventstate->shift) {
restrictbutton_recursive_ebone(
C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
}
@@ -224,7 +225,7 @@ static void restrictbutton_ebone_visibility_fn(bContext *C, void *UNUSED(poin),
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
if (CTX_wm_window(C)->eventstate->ctrl) {
if (CTX_wm_window(C)->eventstate->shift) {
restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
}
@@ -848,8 +849,8 @@ typedef struct RestrictProperties {
PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render;
PropertyRNA *base_hide_viewport;
PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render;
PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only,
*layer_collection_hide_viewport;
PropertyRNA *layer_collection_exclude, *layer_collection_holdout,
*layer_collection_indirect_only, *layer_collection_hide_viewport;
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
PropertyRNA *bone_hide_viewport;
@@ -865,6 +866,7 @@ typedef struct RestrictPropertiesActive {
bool collection_hide_viewport;
bool collection_hide_select;
bool collection_hide_render;
bool layer_collection_exclude;
bool layer_collection_holdout;
bool layer_collection_indirect_only;
bool layer_collection_hide_viewport;
@@ -954,8 +956,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
NULL;
Collection *collection = outliner_collection_from_tree_element(te);
if ((collection->flag & COLLECTION_IS_MASTER) ||
(layer_collection && ((layer_collection->flag & LAYER_COLLECTION_EXCLUDE) != 0))) {
if (collection->flag & COLLECTION_IS_MASTER) {
return false;
}
@@ -995,6 +996,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
"hide_viewport");
props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select");
props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render");
props.layer_collection_exclude = RNA_struct_type_find_property(&RNA_LayerCollection,
"exclude");
props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection,
"holdout");
props.layer_collection_indirect_only = RNA_struct_type_find_property(&RNA_LayerCollection,
@@ -1012,6 +1015,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
struct {
int enable;
int select;
int hide;
int viewport;
@@ -1042,6 +1046,11 @@ static void outliner_draw_restrictbuts(uiBlock *block,
if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
}
if (space_outliner->outlinevis == SO_VIEW_LAYER &&
space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
restrict_offsets.enable = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
}
BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) ==
outliner_restrict_columns_width(space_outliner));
@@ -1430,6 +1439,26 @@ static void outliner_draw_restrictbuts(uiBlock *block,
Collection *collection = outliner_collection_from_tree_element(te);
if (layer_collection != NULL) {
if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
bt = uiDefIconButR_prop(block,
UI_BTYPE_ICON_TOGGLE,
0,
0,
(int)(region->v2d.cur.xmax) - restrict_offsets.enable,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
&layer_collection_ptr,
props.layer_collection_exclude,
-1,
0,
0,
0,
0,
NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
bt = uiDefIconButR_prop(block,
UI_BTYPE_ICON_TOGGLE,
@@ -1823,7 +1852,6 @@ static void outliner_buttons(const bContext *C,
const float restrict_column_width,
TreeElement *te)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
uiBut *bt;
TreeStoreElem *tselem;
int spx, dx, len;
@@ -1849,10 +1877,6 @@ static void outliner_buttons(const bContext *C,
}
spx = te->xs + 1.8f * UI_UNIT_X;
if ((tselem->type == TSE_LAYER_COLLECTION) &&
(space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)) {
spx += UI_UNIT_X;
}
dx = region->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X);
bt = uiDefBut(block,
@@ -1880,6 +1904,143 @@ static void outliner_buttons(const bContext *C,
}
}
static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED(arg2))
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
TreeStoreElem *tselem = (TreeStoreElem *)tselem_poin;
TreeViewContext tvc;
outliner_viewcontext_init(C, &tvc);
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
if (!te) {
return;
}
outliner_item_mode_toggle(C, &tvc, te);
}
/* Return the icon for a given interaction mode
* Should this be more generic (in a different file?) */
static int outliner_get_mode_icon(const int mode)
{
switch (mode) {
case OB_MODE_OBJECT:
return ICON_OBJECT_DATAMODE;
case OB_MODE_EDIT:
case OB_MODE_EDIT_GPENCIL:
return ICON_EDITMODE_HLT;
case OB_MODE_SCULPT:
case OB_MODE_SCULPT_GPENCIL:
return ICON_SCULPTMODE_HLT;
case OB_MODE_VERTEX_PAINT:
case OB_MODE_VERTEX_GPENCIL:
return ICON_VPAINT_HLT;
case OB_MODE_WEIGHT_PAINT:
case OB_MODE_WEIGHT_GPENCIL:
return ICON_WPAINT_HLT;
case OB_MODE_TEXTURE_PAINT:
return ICON_TPAINT_HLT;
case OB_MODE_PARTICLE_EDIT:
return ICON_PARTICLEMODE;
case OB_MODE_POSE:
return ICON_POSE_HLT;
case OB_MODE_PAINT_GPENCIL:
return ICON_GREASEPENCIL;
default:
return ICON_DOT;
}
}
/* Draw icons for adding and removing objects from the current interation mode */
static void outliner_draw_mode_column_toggle(uiBlock *block,
TreeViewContext *tvc,
TreeElement *te,
TreeStoreElem *tselem,
const bool lock_object_modes)
{
uiBut *but;
const int active_mode = tvc->obact->mode;
bool draw_active_icon = true;
if (tselem->type == 0 && te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
/* When not locking object modes, objects can remain in non-object modes. For modes that do not
* allow multi-object editing, these other objects should still show be viewed as not in the
* mode. Otherwise multiple objects show the same mode icon in the outliner even though only
* one object is actually editable in the mode. */
if (!lock_object_modes && ob != tvc->obact && !(tvc->ob_edit || tvc->ob_pose)) {
draw_active_icon = false;
}
if (ob->type == tvc->obact->type) {
if (draw_active_icon && ob->mode == tvc->obact->mode) {
but = uiDefIconBut(block,
UI_BTYPE_ICON_TOGGLE,
0,
outliner_get_mode_icon(active_mode),
0,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Remove from the current mode"));
UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL);
UI_but_flag_enable(but, UI_BUT_DRAG_LOCK);
}
else {
/* Not all objects have particle systems */
if (active_mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) {
return;
}
but = uiDefIconBut(block,
UI_BTYPE_ICON_TOGGLE,
0,
tselem->flag & TSE_HIGHLIGHTED ? outliner_get_mode_icon(active_mode) :
ICON_DOT,
0,
te->ys,
UI_UNIT_X,
UI_UNIT_Y,
NULL,
0.0,
0.0,
0.0,
0.0,
TIP_("Add to the current mode"));
UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL);
UI_but_flag_enable(but, UI_BUT_DRAG_LOCK);
}
}
}
}
static void outliner_draw_mode_column(const bContext *C,
uiBlock *block,
TreeViewContext *tvc,
SpaceOutliner *space_outliner,
ListBase *tree)
{
TreeStoreElem *tselem;
const bool lock_object_modes = tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK;
LISTBASE_FOREACH (TreeElement *, te, tree) {
tselem = TREESTORE(te);
if (tvc->obact && tvc->obact->mode != OB_MODE_OBJECT) {
outliner_draw_mode_column_toggle(block, tvc, te, tselem, lock_object_modes);
}
if (TSELEM_OPEN(tselem, space_outliner)) {
outliner_draw_mode_column(C, block, tvc, space_outliner, &te->subtree);
}
}
}
/* ****************************************************** */
/* Normal Drawing... */
@@ -1916,9 +2077,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
break;
case TSE_CONSTRAINT_BASE:
data.icon = ICON_CONSTRAINT;
data.drag_id = tselem->id;
break;
case TSE_CONSTRAINT: {
bConstraint *con = te->directdata;
data.drag_id = tselem->id;
switch ((eBConstraint_Types)con->type) {
case CONSTRAINT_TYPE_CAMERASOLVER:
data.icon = ICON_CON_CAMERASOLVER;
@@ -2013,6 +2176,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
}
case TSE_MODIFIER_BASE:
data.icon = ICON_MODIFIER_DATA;
data.drag_id = tselem->id;
break;
case TSE_LINKED_OB:
data.icon = ICON_OBJECT_DATA;
@@ -2022,6 +2186,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
break;
case TSE_MODIFIER: {
Object *ob = (Object *)tselem->id;
data.drag_id = tselem->id;
if (ob->type != OB_GPENCIL) {
ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
switch ((ModifierType)md->type) {
@@ -2188,7 +2354,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr);
switch ((GpencilModifierType)md->type) {
case eGpencilModifierType_Noise:
data.icon = ICON_RNDCURVE;
data.icon = ICON_MOD_NOISE;
break;
case eGpencilModifierType_Subdiv:
data.icon = ICON_MOD_SUBSURF;
@@ -2232,6 +2398,15 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eGpencilModifierType_Armature:
data.icon = ICON_MOD_ARMATURE;
break;
case eGpencilModifierType_Multiply:
data.icon = ICON_GP_MULTIFRAME_EDITING;
break;
case eGpencilModifierType_Time:
data.icon = ICON_MOD_TIME;
break;
case eGpencilModifierType_Texture:
data.icon = ICON_TEXTURE;
break;
/* Default */
default:
@@ -2347,13 +2522,18 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
}
data.icon = ICON_GROUP;
data.icon = ICON_OUTLINER_COLLECTION;
break;
}
case TSE_GP_LAYER: {
data.icon = ICON_OUTLINER_DATA_GP_LAYER;
break;
}
case TSE_EFFECT_BASE:
case TSE_EFFECT:
data.drag_id = tselem->id;
data.icon = ICON_SHADERFX;
break;
default:
data.icon = ICON_DOT;
break;
@@ -2578,60 +2758,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
return data;
}
static void tselem_draw_layer_collection_enable_icon(
Scene *scene, uiBlock *block, int xmax, float x, float y, TreeElement *te, float alpha)
{
/* Get RNA property (once for speed). */
static PropertyRNA *exclude_prop = NULL;
if (exclude_prop == NULL) {
exclude_prop = RNA_struct_type_find_property(&RNA_LayerCollection, "exclude");
}
if (x >= xmax) {
/* Placement of icons, copied from interface_widgets.c. */
float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
x += 2.0f * aspect;
y += 2.0f * aspect;
/* restrict column clip... it has been coded by simply overdrawing,
* doesn't work for buttons */
uchar color[4];
int icon = RNA_property_ui_icon(exclude_prop);
if (UI_icon_get_theme_color(icon, color)) {
UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, color, true);
}
else {
UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
}
}
else {
LayerCollection *layer_collection = te->directdata;
PointerRNA layer_collection_ptr;
RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr);
char emboss = UI_block_emboss_get(block);
UI_block_emboss_set(block, UI_EMBOSS_NONE);
uiBut *bt = uiDefIconButR_prop(block,
UI_BTYPE_ICON_TOGGLE,
0,
0,
x,
y,
UI_UNIT_X,
UI_UNIT_Y,
&layer_collection_ptr,
exclude_prop,
-1,
0,
0,
0,
0,
NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_block_emboss_set(block, emboss);
}
}
static void tselem_draw_icon(uiBlock *block,
int xmax,
float x,
@@ -2647,8 +2773,30 @@ static void tselem_draw_icon(uiBlock *block,
return;
}
if (outliner_is_collection_tree_element(te)) {
Collection *collection = outliner_collection_from_tree_element(te);
/* placement of icons, copied from interface_widgets.c */
float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
x += 2.0f * aspect;
y += 2.0f * aspect;
if (collection->color != COLLECTION_COLOR_NONE) {
bTheme *btheme = UI_GetTheme();
UI_icon_draw_ex(x,
y,
data.icon,
U.inv_dpi_fac,
alpha,
0.0f,
btheme->collection_color[collection->color - 1].color,
true);
}
else {
UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, true);
}
}
/* Icon is covered by restrict buttons */
if (!is_clickable || x >= xmax) {
else if (!is_clickable || x >= xmax) {
/* Reduce alpha to match icon buttons */
alpha *= 0.8f;
@@ -2732,15 +2880,21 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
GPU_blend(GPU_BLEND_ALPHA); /* Roundbox and text drawing disables. */
}
static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
static void outliner_draw_active_highlight(const float minx,
const float miny,
const float maxx,
const float maxy)
{
float text[4];
UI_GetThemeColor4fv(TH_TEXT, text);
const float ufac = U.pixelsize;
float icon_border[4];
UI_GetThemeColor4fv(TH_TEXT, icon_border);
icon_border[3] = 0.6f;
copy_v3_v3(icon_color, text);
icon_color[3] = 0.4f;
copy_v3_v3(icon_border, text);
icon_border[3] = 0.2f;
/* border around it */
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_aa(
false, minx + ufac, miny + ufac, maxx - ufac, maxy - ufac, UI_UNIT_Y / 4.0f, icon_border);
GPU_blend(true); /* Roundbox disables. */
}
/* Draw a rounded rectangle behind icons of active elements. */
@@ -2773,19 +2927,8 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
TreeStoreElem *tselem = TREESTORE(te);
if (active != OL_DRAWSEL_NONE) {
float icon_color[4], icon_border[4];
outliner_icon_background_colors(icon_color, icon_border);
if (active == OL_DRAWSEL_ACTIVE) {
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color);
icon_border[3] = 0.3f;
}
outliner_draw_active_indicator((float)*offsx,
(float)ys,
(float)*offsx + UI_UNIT_X,
(float)ys + UI_UNIT_Y,
icon_color,
icon_border);
outliner_draw_active_highlight(
(float)*offsx, (float)ys, (float)*offsx + UI_UNIT_X, (float)ys + UI_UNIT_Y);
}
if (tselem->flag & TSE_HIGHLIGHTED) {
@@ -2967,8 +3110,6 @@ static void outliner_draw_tree_element(bContext *C,
eOLDrawState active = OL_DRAWSEL_NONE;
uchar text_color[4];
UI_GetThemeColor4ubv(TH_TEXT, text_color);
float icon_bgcolor[4], icon_border[4];
outliner_icon_background_colors(icon_bgcolor, icon_border);
if (*starty + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && *starty <= region->v2d.cur.ymax) {
const float alpha_fac = ((te->flag & TE_DISABLED) || (te->flag & TE_CHILD_NOT_IN_COLLECTION) ||
@@ -2993,7 +3134,6 @@ static void outliner_draw_tree_element(bContext *C,
if (te->idcode == ID_SCE) {
if (tselem->id == (ID *)tvc->scene) {
/* active scene */
icon_bgcolor[3] = 0.2f;
active = OL_DRAWSEL_ACTIVE;
}
}
@@ -3022,14 +3162,11 @@ static void outliner_draw_tree_element(bContext *C,
}
else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
/* objects being edited */
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_bgcolor);
icon_border[3] = 0.3f;
active = OL_DRAWSEL_ACTIVE;
}
else {
if (tree_element_active(C, tvc, space_outliner, te, OL_SETSEL_NONE, false)) {
/* active items like camera or material */
icon_bgcolor[3] = 0.2f;
active = OL_DRAWSEL_ACTIVE;
}
}
@@ -3037,32 +3174,20 @@ static void outliner_draw_tree_element(bContext *C,
else if (tselem->type == TSE_GP_LAYER) {
/* Active grease pencil layer. */
if (((bGPDlayer *)te->directdata)->flag & GP_LAYER_ACTIVE) {
icon_bgcolor[3] = 0.2f;
active = OL_DRAWSEL_ACTIVE;
}
}
else {
active = tree_element_type_active(C, tvc, space_outliner, te, tselem, OL_SETSEL_NONE, false);
/* active collection*/
icon_bgcolor[3] = 0.2f;
}
/* Checkbox to enable collections. */
if ((tselem->type == TSE_LAYER_COLLECTION) &&
(space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)) {
tselem_draw_layer_collection_enable_icon(
tvc->scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f);
offsx += UI_UNIT_X;
}
/* active circle */
if (active != OL_DRAWSEL_NONE) {
outliner_draw_active_indicator((float)startx + offsx + UI_UNIT_X,
outliner_draw_active_highlight((float)startx + offsx + UI_UNIT_X,
(float)*starty,
(float)startx + offsx + 2.0f * UI_UNIT_X,
(float)*starty + UI_UNIT_Y,
icon_bgcolor,
icon_border);
(float)*starty + UI_UNIT_Y);
te->flag |= TE_ACTIVE; /* For lookup in display hierarchies. */
}
@@ -3125,7 +3250,8 @@ static void outliner_draw_tree_element(bContext *C,
offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
/* closed item, we draw the icons, not when it's a scene, or master-server list though */
if (!TSELEM_OPEN(tselem, space_outliner)) {
if (!TSELEM_OPEN(tselem, space_outliner) &&
!(space_outliner->filter & SO_FILTER_NO_ROW_CHILDREN)) {
if (te->subtree.first) {
if (tselem->type == 0 && te->idcode == ID_SCE) {
/* pass */
@@ -3190,6 +3316,17 @@ static void outliner_draw_tree_element(bContext *C,
}
}
static bool subtree_contains_object(ListBase *lb)
{
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
return true;
}
}
return false;
}
static void outliner_draw_hierarchy_lines_recursive(uint pos,
SpaceOutliner *space_outliner,
ListBase *lb,
@@ -3198,100 +3335,50 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos,
bool draw_grayed_out,
int *starty)
{
TreeElement *te, *te_vertical_line_last = NULL, *te_vertical_line_last_dashed = NULL;
int y1, y2, y1_dashed, y2_dashed;
bTheme *btheme = UI_GetTheme();
int y = *starty;
short color = 0;
if (BLI_listbase_is_empty(lb)) {
return;
}
/* Small vertical padding */
const short line_padding = UI_UNIT_Y / 4.0f;
struct {
int steps_num;
int step_len;
int gap_len;
} dash = {
.steps_num = 4,
};
dash.step_len = UI_UNIT_X / dash.steps_num;
dash.gap_len = dash.step_len / 2;
const uchar grayed_alpha = col[3] / 2;
/* For vertical lines between objects. */
y1 = y2 = y1_dashed = y2_dashed = *starty;
for (te = lb->first; te; te = te->next) {
bool draw_children_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING);
/* Draw vertical lines between collections */
bool draw_hierarchy_line;
LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (draw_children_grayed_out) {
immUniformColor3ubvAlpha(col, grayed_alpha);
}
else {
immUniformColor4ubv(col);
}
if ((te->flag & TE_CHILD_NOT_IN_COLLECTION) == 0) {
/* Horizontal Line? */
if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) {
immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - U.pixelsize);
/* Vertical Line? */
if (te->idcode == ID_OB) {
te_vertical_line_last = te;
y2 = *starty;
}
y1_dashed = *starty - UI_UNIT_Y;
}
}
else {
BLI_assert(te->idcode == ID_OB);
/* Horizontal line - dashed. */
int start = startx;
for (int i = 0; i < dash.steps_num; i++) {
immRecti(pos, start, *starty, start + dash.step_len - dash.gap_len, *starty - U.pixelsize);
start += dash.step_len;
}
te_vertical_line_last_dashed = te;
y2_dashed = *starty;
}
draw_hierarchy_line = false;
*starty -= UI_UNIT_Y;
if (TSELEM_OPEN(tselem, space_outliner)) {
outliner_draw_hierarchy_lines_recursive(pos,
space_outliner,
&te->subtree,
startx + UI_UNIT_X,
col,
draw_children_grayed_out,
starty);
/* Only draw hierarchy lines for open collections. */
if (TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
if (tselem->type == TSE_LAYER_COLLECTION) {
draw_hierarchy_line = true;
Collection *collection = outliner_collection_from_tree_element(te);
color = collection->color;
y = *starty;
}
else if (tselem->type == 0 && te->idcode == ID_OB) {
if (subtree_contains_object(&te->subtree)) {
draw_hierarchy_line = true;
y = *starty;
}
}
outliner_draw_hierarchy_lines_recursive(
pos, space_outliner, &te->subtree, startx + UI_UNIT_X, col, draw_grayed_out, starty);
}
}
if (draw_grayed_out) {
immUniformColor3ubvAlpha(col, grayed_alpha);
}
else {
immUniformColor4ubv(col);
}
if (draw_hierarchy_line) {
if (color != COLLECTION_COLOR_NONE) {
immUniformColor4ubv(btheme->collection_color[color - 1].color);
}
else {
immUniformColor4ubv(col);
}
/* Vertical line. */
te = te_vertical_line_last;
if ((te != NULL) && (te->parent || lb->first != lb->last)) {
immRecti(pos, startx, y1 + UI_UNIT_Y, startx + U.pixelsize, y2);
}
/* Children that are not in the collection are always in the end of the subtree.
* This way we can draw their own dashed vertical lines. */
te = te_vertical_line_last_dashed;
if ((te != NULL) && (te->parent || lb->first != lb->last)) {
const int steps_num = ((y1_dashed + UI_UNIT_Y) - y2_dashed) / dash.step_len;
int start = y1_dashed + UI_UNIT_Y;
for (int i = 0; i < steps_num; i++) {
immRecti(pos, startx, start, startx + U.pixelsize, start - dash.step_len + dash.gap_len);
start -= dash.step_len;
immRecti(pos, startx, y - line_padding, startx + (U.pixelsize * 1), *starty + line_padding);
}
}
}
@@ -3356,8 +3443,20 @@ static void outliner_draw_struct_marks(ARegion *region,
}
}
static void outliner_draw_highlights_recursive(uint pos,
const ARegion *region,
static void draw_line_highlight(int x, int y, int maxx, int maxy, const float color[4])
{
const float pad = U.pixelsize;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_aa(true,
(float)x + pad,
(float)y + pad,
(float)maxx - (pad * 2), /* Extra offset needed on right. */
(float)maxy - pad,
5.0f,
color);
}
static void outliner_draw_highlights_recursive(const ARegion *region,
const SpaceOutliner *space_outliner,
const ListBase *lb,
const float col_selection[4],
@@ -3374,20 +3473,19 @@ static void outliner_draw_highlights_recursive(uint pos,
LISTBASE_FOREACH (TreeElement *, te, lb) {
const TreeStoreElem *tselem = TREESTORE(te);
const int start_y = *io_start_y;
const int end_x = (int)region->v2d.cur.xmax;
/* selection status */
if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
immUniformColor4fv(col_active);
immRecti(pos, 0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y);
draw_line_highlight(0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y, col_active);
}
else if (tselem->flag & TSE_SELECTED) {
immUniformColor4fv(col_selection);
immRecti(pos, 0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y);
draw_line_highlight(
0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y, col_selection);
}
/* highlights */
if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) {
const int end_x = (int)region->v2d.cur.xmax;
if (tselem->flag & TSE_DRAG_ANY) {
/* drag and drop highlight */
@@ -3395,20 +3493,18 @@ static void outliner_draw_highlights_recursive(uint pos,
UI_GetThemeColorShade4fv(TH_BACK, -40, col);
if (tselem->flag & TSE_DRAG_BEFORE) {
immUniformColor4fv(col);
immRecti(pos,
start_x,
start_y + UI_UNIT_Y - U.pixelsize,
end_x,
start_y + UI_UNIT_Y + U.pixelsize);
draw_line_highlight(start_x,
start_y + UI_UNIT_Y - (U.pixelsize * 2),
end_x,
start_y + UI_UNIT_Y + (U.pixelsize * 2),
col);
}
else if (tselem->flag & TSE_DRAG_AFTER) {
immUniformColor4fv(col);
immRecti(pos, start_x, start_y - U.pixelsize, end_x, start_y + U.pixelsize);
draw_line_highlight(
start_x, start_y - (U.pixelsize * 2), end_x, start_y + (U.pixelsize * 2), col);
}
else {
immUniformColor3fvAlpha(col, col[3] * 0.5f);
immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
draw_line_highlight(start_x, start_y, end_x, start_y + UI_UNIT_Y, col);
}
}
else {
@@ -3416,21 +3512,18 @@ static void outliner_draw_highlights_recursive(uint pos,
/* search match highlights
* we don't expand items when searching in the data-blocks but we
* still want to highlight any filter matches. */
immUniformColor4fv(col_searchmatch);
immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
draw_line_highlight(start_x, start_y, end_x, start_y + UI_UNIT_Y, col_searchmatch);
}
else if (tselem->flag & TSE_HIGHLIGHTED) {
/* mouse hover highlight */
immUniformColor4fv(col_highlight);
immRecti(pos, 0, start_y, end_x, start_y + UI_UNIT_Y);
draw_line_highlight(0, start_y, end_x, start_y + UI_UNIT_Y, col_highlight);
}
}
}
*io_start_y -= UI_UNIT_Y;
if (TSELEM_OPEN(tselem, space_outliner)) {
outliner_draw_highlights_recursive(pos,
region,
outliner_draw_highlights_recursive(region,
space_outliner,
&te->subtree,
col_selection,
@@ -3440,6 +3533,10 @@ static void outliner_draw_highlights_recursive(uint pos,
start_x + UI_UNIT_X,
io_start_y);
}
else if (outliner_find_element_with_flag(&te->subtree, TSE_ACTIVE)) {
/* Parent highlight for active element in collapsed subtree. */
draw_line_highlight(0, start_y, end_x, start_y + UI_UNIT_Y, col_highlight);
}
}
}
@@ -3451,19 +3548,12 @@ static void outliner_draw_highlights(ARegion *region,
const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
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_SELECT_HIGHLIGHT, col_selection);
UI_GetThemeColor4fv(TH_SELECT_ACTIVE, col_active);
UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
col_searchmatch[3] = 0.5f;
GPU_blend(GPU_BLEND_ALPHA);
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,
region,
outliner_draw_highlights_recursive(region,
space_outliner,
&space_outliner->tree,
col_selection,
@@ -3472,8 +3562,6 @@ static void outliner_draw_highlights(ARegion *region,
col_searchmatch,
startx,
starty);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
static void outliner_draw_tree(bContext *C,
@@ -3482,11 +3570,20 @@ static void outliner_draw_tree(bContext *C,
ARegion *region,
SpaceOutliner *space_outliner,
const float restrict_column_width,
const bool use_mode_column,
TreeElement **te_edit)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
int starty, startx;
/* Move the tree a unit left in view layer mode */
short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
UI_UNIT_X :
0;
if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) {
mode_column_offset -= UI_UNIT_X;
}
GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
if (space_outliner->outlinevis == SO_DATA_API) {
@@ -3511,13 +3608,13 @@ static void outliner_draw_tree(bContext *C,
}
/* Gray hierarchy lines. */
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET;
startx = UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET;
startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty);
/* Items themselves. */
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = 0;
startx = mode_column_offset;
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
outliner_draw_tree_element(C,
block,
@@ -3640,12 +3737,22 @@ void draw_outliner(const bContext *C)
/* set matrix for 2d-view controls */
UI_view2d_view_ortho(v2d);
/* Only show mode column in View Layers and Scenes view */
const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) &&
(ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES));
/* draw outliner stuff (background, hierarchy lines and names) */
const float restrict_column_width = outliner_restrict_columns_width(space_outliner);
outliner_back(region);
block = UI_block_begin(C, region, __func__, UI_EMBOSS);
outliner_draw_tree(
(bContext *)C, block, &tvc, region, space_outliner, restrict_column_width, &te_edit);
outliner_draw_tree((bContext *)C,
block,
&tvc,
region,
space_outliner,
restrict_column_width,
use_mode_column,
&te_edit);
/* Compute outliner dimensions after it has been drawn. */
int tree_width, tree_height;
@@ -3680,6 +3787,11 @@ void draw_outliner(const bContext *C)
props_active);
}
/* Draw mode icons */
if (use_mode_column) {
outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
}
UI_block_emboss_set(block, UI_EMBOSS);
/* Draw edit buttons if necessary. */

View File

@@ -284,61 +284,6 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Object Mode Enter/Exit Utilities
* \{ */
static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obact = OBACT(view_layer);
if ((ob->type != obact->type) || ID_IS_LINKED(ob->data)) {
return;
}
if (((ob->mode & obact->mode) != 0) == enter) {
return;
}
if (ob == obact) {
BKE_report(reports, RPT_WARNING, "Active object mode not changed");
return;
}
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base == NULL) {
return;
}
Scene *scene = CTX_data_scene(C);
outliner_object_mode_toggle(C, scene, view_layer, base);
}
void item_object_mode_enter_fn(bContext *C,
ReportList *reports,
Scene *UNUSED(scene),
TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
Object *ob = (Object *)tselem->id;
item_object_mode_enter_exit(C, reports, ob, true);
}
void item_object_mode_exit_fn(bContext *C,
ReportList *reports,
Scene *UNUSED(scene),
TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep),
TreeStoreElem *tselem,
void *UNUSED(user_data))
{
Object *ob = (Object *)tselem->id;
item_object_mode_enter_exit(C, reports, ob, false);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Rename Operator
* \{ */

View File

@@ -222,7 +222,6 @@ typedef enum TreeItemSelectAction {
OL_ITEM_ACTIVATE = (1 << 2), /* Activate the item */
OL_ITEM_EXTEND = (1 << 3), /* Extend the current selection */
OL_ITEM_RECURSIVE = (1 << 4), /* Select recursively */
OL_ITEM_TOGGLE_MODE = (1 << 5) /* Temporary */
} TreeItemSelectAction;
/* outliner_tree.c ----------------------------------------------- */
@@ -277,18 +276,18 @@ eOLDrawState tree_element_active(struct bContext *C,
const eOLSetState set,
const bool handle_all_types);
struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te);
void outliner_item_select(struct bContext *C,
struct SpaceOutliner *space_outliner,
struct TreeElement *te,
const short select_flag);
void outliner_object_mode_toggle(struct bContext *C,
Scene *scene,
ViewLayer *view_layer,
Base *base);
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x);
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x);
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2]);
void outliner_item_mode_toggle(struct bContext *C, TreeViewContext *tvc, TreeElement *te);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_fn)(struct bContext *C,
@@ -384,6 +383,7 @@ void OUTLINER_OT_parent_drop(struct wmOperatorType *ot);
void OUTLINER_OT_parent_clear(struct wmOperatorType *ot);
void OUTLINER_OT_scene_drop(struct wmOperatorType *ot);
void OUTLINER_OT_material_drop(struct wmOperatorType *ot);
void OUTLINER_OT_uistack_drop(struct wmOperatorType *ot);
void OUTLINER_OT_collection_drop(struct wmOperatorType *ot);
/* ...................................................... */
@@ -482,6 +482,8 @@ void OUTLINER_OT_collection_disable_render(struct wmOperatorType *ot);
void OUTLINER_OT_hide(struct wmOperatorType *ot);
void OUTLINER_OT_unhide_all(struct wmOperatorType *ot);
void OUTLINER_OT_collection_color_tag_set(struct wmOperatorType *ot);
/* outliner_utils.c ---------------------------------------------- */
void outliner_viewcontext_init(const struct bContext *C, TreeViewContext *tvc);

View File

@@ -88,6 +88,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_parent_clear);
WM_operatortype_append(OUTLINER_OT_scene_drop);
WM_operatortype_append(OUTLINER_OT_material_drop);
WM_operatortype_append(OUTLINER_OT_uistack_drop);
WM_operatortype_append(OUTLINER_OT_collection_drop);
/* collections */
@@ -117,6 +118,8 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_collection_show_inside);
WM_operatortype_append(OUTLINER_OT_hide);
WM_operatortype_append(OUTLINER_OT_unhide_all);
WM_operatortype_append(OUTLINER_OT_collection_color_tag_set);
}
void outliner_keymap(wmKeyConfig *keyconf)

View File

@@ -27,12 +27,16 @@
#include "DNA_armature_types.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
#include "DNA_material_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
#include "DNA_world_types.h"
#include "BLI_listbase.h"
@@ -46,6 +50,7 @@
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_workspace.h"
@@ -54,6 +59,7 @@
#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
#include "ED_buttons.h"
#include "ED_gpencil.h"
#include "ED_object.h"
#include "ED_outliner.h"
@@ -73,183 +79,137 @@
#include "outliner_intern.h"
static bool do_outliner_activate_common(bContext *C,
Main *bmain,
Depsgraph *depsgraph,
Scene *scene,
ViewLayer *view_layer,
Base *base,
const bool extend,
const bool do_exit)
/**
* Find a new active object to keep the other objects in the mode.
*
* Identify other objects in the tree that are also in the interaction mode
* and set the next (circular) as the active object. If none are found, then
* the mode should be exited.
*/
static bool outliner_set_new_active(bContext *C, ListBase *tree, Object *ob, int mode)
{
bool use_all = false;
ViewLayer *view_layer = CTX_data_view_layer(C);
if (do_exit) {
FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
ED_object_mode_generic_exit(bmain, depsgraph, scene, ob_iter);
LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
Object *ob_te = (Object *)tselem->id;
/* If an object is found in the mode and not the current element. */
if (ob_te->mode == mode && ob_te != ob) {
Base *base = BKE_view_layer_base_find(view_layer, ob_te);
ED_object_base_activate(C, base);
return true;
}
}
if (outliner_set_new_active(C, &te->subtree, ob, mode)) {
return true;
}
FOREACH_OBJECT_END;
}
/* Just like clicking in the object changes the active object,
* clicking on the object data should change it as well. */
ED_object_base_activate(C, base);
if (extend) {
use_all = true;
}
else {
ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT);
}
return use_all;
return false;
}
/**
* Bring the newly selected object into edit mode.
* Bring the newly selected object into edit mode and activate it.
*
* If extend is used, we try to have the other compatible selected objects in the new mode as well.
* Otherwise only the new object will be active, selected and in the edit mode.
* If extend is used, we try to have the other compatible selected objects in the new mode as
* well. Otherwise only the new object will be active, selected and in the edit mode.
*/
static void do_outliner_item_editmode_toggle(
bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend)
static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *base)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact = OBACT(view_layer);
Object *ob = base->object;
bool use_all = false;
bool ok = false;
if (obact == NULL) {
ED_object_base_activate(C, base);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
obact = ob;
use_all = true;
}
else if (obact->data == ob->data) {
use_all = true;
}
else if (obact->mode == OB_MODE_OBJECT) {
use_all = do_outliner_activate_common(
C, bmain, depsgraph, scene, view_layer, base, extend, false);
}
else if ((ob->type != obact->type) || ((obact->mode & OB_MODE_EDIT) == 0) ||
((obact->mode & OB_MODE_POSE) && ELEM(OB_ARMATURE, ob->type, obact->type)) || !extend) {
use_all = do_outliner_activate_common(
C, bmain, depsgraph, scene, view_layer, base, extend, true);
}
if (BKE_object_is_in_editmode(ob)) {
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
outliner_set_new_active(C, &space_outliner->tree, ob, ob->mode);
if (use_all) {
WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
}
else {
bool ok;
if (BKE_object_is_in_editmode(ob)) {
ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
}
else {
ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT);
}
if (ok) {
ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT);
}
if (ok) {
ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
}
static void do_outliner_item_posemode_toggle(
bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend)
static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *base)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact = OBACT(view_layer);
Object *ob = base->object;
bool use_all = false;
if (obact == NULL) {
ED_object_base_activate(C, base);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
obact = ob;
use_all = true;
}
else if (obact->data == ob->data) {
use_all = true;
}
else if (obact->mode == OB_MODE_OBJECT) {
use_all = do_outliner_activate_common(
C, bmain, depsgraph, scene, view_layer, base, extend, false);
}
else if ((!ELEM(ob->type, obact->type)) ||
((obact->mode & OB_MODE_EDIT) && ELEM(OB_ARMATURE, ob->type, obact->type))) {
use_all = do_outliner_activate_common(
C, bmain, depsgraph, scene, view_layer, base, extend, true);
}
bool ok = false;
if (ob->mode & OB_MODE_POSE) {
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
outliner_set_new_active(C, &space_outliner->tree, ob, ob->mode);
if (use_all) {
WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
ok = ED_object_posemode_exit_ex(bmain, ob);
}
else {
bool ok = false;
if (ob->mode & OB_MODE_POSE) {
ok = ED_object_posemode_exit_ex(bmain, ob);
}
else {
ok = ED_object_posemode_enter_ex(bmain, ob);
}
if (ok) {
ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
ok = ED_object_posemode_enter_ex(bmain, ob);
ED_object_base_activate(C, base);
}
if (ok) {
ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
}
/* For draw callback to run mode switching */
void outliner_object_mode_toggle(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base)
/* Toggle interaction mode for modes that do not allow multi-object editing */
static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base)
{
Object *obact = OBACT(view_layer);
if (obact->mode & OB_MODE_EDIT) {
do_outliner_item_editmode_toggle(C, scene, view_layer, base, true);
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
const int active_mode = tvc->obact->mode;
/* Remove the active object from the mode */
if (tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
ED_object_mode_generic_exit(bmain, depsgraph, tvc->scene, tvc->obact);
}
else if (obact->mode & OB_MODE_POSE) {
do_outliner_item_posemode_toggle(C, scene, view_layer, base, true);
Base *base_old = BKE_view_layer_base_find(tvc->view_layer, tvc->obact);
if (base_old) {
ED_object_base_select(base_old, BA_DESELECT);
}
ED_object_base_activate(C, base);
ED_object_base_select(base, BA_SELECT);
ED_object_mode_set(C, active_mode);
ED_outliner_select_sync_from_object_tag(C);
}
/* Toggle the item's interaction mode if supported */
static void outliner_item_mode_toggle(bContext *C,
TreeViewContext *tvc,
TreeElement *te,
const bool extend)
void outliner_item_mode_toggle(bContext *C, TreeViewContext *tvc, TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0) {
if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) {
Object *ob = (Object *)outliner_search_back(te, ID_OB);
if ((ob != NULL) && (ob->data == tselem->id)) {
Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
do_outliner_item_editmode_toggle(C, tvc->scene, tvc->view_layer, base, extend);
}
}
}
else if (ELEM(te->idcode, ID_GD)) {
/* set grease pencil to object mode */
WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
}
}
else if (tselem->type == TSE_POSE_BASE) {
if (tselem->type == 0 && te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
if (base != NULL) {
do_outliner_item_posemode_toggle(C, tvc->scene, tvc->view_layer, base, extend);
if (!base || !(base->flag & BASE_VISIBLE_DEPSGRAPH)) {
return;
}
if (tvc->ob_edit && OB_TYPE_SUPPORT_EDITMODE(ob->type)) {
do_outliner_item_editmode_toggle(C, tvc->scene, base);
}
else if (tvc->ob_pose && ob->type == OB_ARMATURE) {
do_outliner_item_posemode_toggle(C, tvc->scene, base);
}
else {
do_outliner_item_mode_toggle_generic(C, tvc, base);
}
ED_outliner_select_sync_from_object_tag(C);
}
}
@@ -499,7 +459,7 @@ static eOLDrawState tree_element_active_material(bContext *C,
return OL_DRAWSEL_NONE;
}
static eOLDrawState tree_element_active_camera(bContext *C,
static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
Scene *scene,
ViewLayer *UNUSED(view_layer),
TreeElement *te,
@@ -508,16 +468,6 @@ static eOLDrawState tree_element_active_camera(bContext *C,
Object *ob = (Object *)outliner_search_back(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;
@@ -858,15 +808,26 @@ static eOLDrawState tree_element_active_psys(bContext *C,
}
static int tree_element_active_constraint(bContext *C,
Scene *UNUSED(scene),
ViewLayer *UNUSED(sl),
TreeElement *UNUSED(te),
Scene *scene,
ViewLayer *view_layer,
TreeElement *te,
TreeStoreElem *tselem,
const eOLSetState set)
{
if (set != OL_SETSEL_NONE) {
Object *ob = (Object *)tselem->id;
/* Activate the parent bone if this is a bone constraint. */
te = te->parent;
while (te) {
tselem = TREESTORE(te);
if (tselem->type == TSE_POSE_CHANNEL) {
tree_element_active_posechannel(C, scene, view_layer, ob, te, tselem, set, false);
return OL_DRAWSEL_NONE;
}
te = te->parent;
}
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
}
@@ -1094,6 +1055,7 @@ eOLDrawState tree_element_type_active(bContext *C,
case TSE_POSE_CHANNEL:
return tree_element_active_posechannel(
C, tvc->scene, tvc->view_layer, tvc->ob_pose, te, tselem, set, recursive);
case TSE_CONSTRAINT_BASE:
case TSE_CONSTRAINT:
return tree_element_active_constraint(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_R_LAYER:
@@ -1117,6 +1079,188 @@ eOLDrawState tree_element_type_active(bContext *C,
return OL_DRAWSEL_NONE;
}
bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te)
{
TreeStoreElem *tselem;
te = te->parent;
while (te) {
tselem = TREESTORE(te);
if (tselem->type == TSE_POSE_CHANNEL) {
*r_bone_te = te;
return (bPoseChannel *)te->directdata;
}
te = te->parent;
}
return NULL;
}
static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem)
{
PointerRNA ptr;
/* ID Types */
if (tselem->type == 0) {
RNA_id_pointer_create(tselem->id, &ptr);
switch (te->idcode) {
case ID_SCE:
ED_buttons_set_context(C, &ptr, BCONTEXT_SCENE);
break;
case ID_OB:
ED_buttons_set_context(C, &ptr, BCONTEXT_OBJECT);
break;
case ID_ME:
case ID_CU:
case ID_MB:
case ID_IM:
case ID_LT:
case ID_LA:
case ID_CA:
case ID_KE:
case ID_SPK:
case ID_AR:
case ID_GD:
case ID_LP:
case ID_HA:
case ID_PT:
case ID_VO:
ED_buttons_set_context(C, &ptr, BCONTEXT_DATA);
break;
case ID_MA:
ED_buttons_set_context(C, &ptr, BCONTEXT_MATERIAL);
break;
case ID_WO:
ED_buttons_set_context(C, &ptr, BCONTEXT_WORLD);
break;
}
}
else {
switch (tselem->type) {
case TSE_DEFGROUP_BASE:
case TSE_DEFGROUP:
RNA_id_pointer_create(tselem->id, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_DATA);
break;
case TSE_CONSTRAINT_BASE:
case TSE_CONSTRAINT: {
TreeElement *bone_te = NULL;
bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te);
if (pchan) {
RNA_pointer_create(TREESTORE(bone_te)->id, &RNA_PoseBone, pchan, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_BONE_CONSTRAINT);
}
else {
RNA_id_pointer_create(tselem->id, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_CONSTRAINT);
}
/* Expand the selected constraint in the properties editor. */
if (tselem->type != TSE_CONSTRAINT_BASE) {
bConstraint *con = te->directdata;
con->ui_expand_flag |= (1 << 0);
}
break;
}
case TSE_MODIFIER_BASE:
case TSE_MODIFIER:
RNA_id_pointer_create(tselem->id, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_MODIFIER);
if (tselem->type != TSE_MODIFIER_BASE) {
Object *ob = (Object *)tselem->id;
if (ob->type == OB_GPENCIL) {
GpencilModifierData *md = te->directdata;
md->ui_expand_flag |= (1 << 0);
}
else {
ModifierData *md = te->directdata;
md->ui_expand_flag |= (1 << 0);
}
}
// PropertyRNA *prop = RNA_struct_type_find_property(&RNA_Modifier, "show_expanded");
// RNA_property_boolean_set(&ptr, prop, true);
break;
case TSE_EFFECT_BASE:
case TSE_EFFECT:
RNA_id_pointer_create(tselem->id, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_SHADERFX);
if (tselem->type != TSE_EFFECT_BASE) {
ShaderFxData *sfx = te->directdata;
sfx->ui_expand_flag |= (1 << 0);
}
break;
case TSE_BONE: {
bArmature *arm = (bArmature *)tselem->id;
Bone *bone = te->directdata;
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_BONE);
break;
}
case TSE_EBONE: {
bArmature *arm = (bArmature *)tselem->id;
EditBone *ebone = te->directdata;
RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_BONE);
break;
}
case TSE_POSE_CHANNEL: {
Object *ob = (Object *)tselem->id;
bArmature *arm = ob->data;
bPoseChannel *pchan = te->directdata;
RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_BONE);
break;
}
case TSE_POSE_BASE: {
Object *ob = (Object *)tselem->id;
bArmature *arm = ob->data;
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_DATA);
break;
}
case TSE_R_LAYER_BASE:
case TSE_R_LAYER: {
ViewLayer *view_layer = te->directdata;
RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_VIEW_LAYER);
break;
}
case TSE_POSEGRP_BASE:
case TSE_POSEGRP: {
Object *ob = (Object *)tselem->id;
bArmature *arm = ob->data;
RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_DATA);
break;
}
case TSE_LINKED_PSYS: {
Object *ob = (Object *)tselem->id;
ParticleSystem *psys = psys_get_current(ob);
RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_PARTICLE);
break;
}
case TSE_GP_LAYER:
RNA_id_pointer_create(tselem->id, &ptr);
ED_buttons_set_context(C, &ptr, BCONTEXT_DATA);
break;
}
}
}
/* ================================================ */
/**
@@ -1141,14 +1285,8 @@ static void do_outliner_item_activate_tree_element(bContext *C,
TSE_SEQUENCE_DUP,
TSE_EBONE,
TSE_LAYER_COLLECTION)) {
/* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects,
* we do not want to switch out of edit mode (see T48328 for details). */
}
else if (tselem->id && OB_DATA_SUPPORT_EDITMODE(te->idcode)) {
/* Support edit-mode toggle, keeping the active object as is. */
}
else if (tselem->type == TSE_POSE_BASE) {
/* Support pose mode toggle, keeping the active object as is. */
/* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several
* objects, we do not want to switch out of edit mode (see T48328 for details). */
}
else if (do_activate_data) {
tree_element_set_active_object(C,
@@ -1165,11 +1303,6 @@ static void do_outliner_item_activate_tree_element(bContext *C,
if (do_activate_data == false) {
/* Only select in outliner. */
}
else if (te->idcode == ID_SCE) {
if (tvc->scene != (Scene *)tselem->id) {
WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id);
}
}
else if ((te->idcode == ID_GR) && (space_outliner->outlinevis != SO_VIEW_LAYER)) {
Collection *gr = (Collection *)tselem->id;
@@ -1223,6 +1356,8 @@ static void do_outliner_item_activate_tree_element(bContext *C,
extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
recursive);
}
outliner_set_properties_tab(C, te, tselem);
}
/* Select the item using the set flags */
@@ -1236,7 +1371,8 @@ void outliner_item_select(bContext *C,
const bool extend = select_flag & OL_ITEM_EXTEND;
const bool activate_data = select_flag & OL_ITEM_SELECT_DATA;
/* Clear previous active when activating and clear selection when not extending selection */
/* Clear previous active when activating and clear selection when not extending selection
*/
const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED);
if (clear_flag) {
outliner_flag_set(&space_outliner->tree, clear_flag, false);
@@ -1262,11 +1398,6 @@ void outliner_item_select(bContext *C,
extend,
select_flag & OL_ITEM_RECURSIVE,
activate_data || space_outliner->flag & SO_SYNC_SELECT);
/* Mode toggle on data activate for now, but move later */
if (select_flag & OL_ITEM_TOGGLE_MODE) {
outliner_item_mode_toggle(C, &tvc, te, extend);
}
}
}
@@ -1327,7 +1458,8 @@ static void do_outliner_range_select(bContext *C,
return;
}
/* If active is not selected or visible, select and activate the element under the cursor */
/* If active is not selected or visible, select and activate the element under the cursor
*/
if (!active_selected || !outliner_is_element_visible(active)) {
outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
return;
@@ -1343,6 +1475,16 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_ou
return (view_co_x > region->v2d.cur.xmax - outliner_restrict_columns_width(space_outliner));
}
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
{
/* Mode toggles only show in View Layer and Scenes modes. */
if (!ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)) {
return false;
}
return space_outliner->flag & SO_MODE_COLUMN && view_mval[0] < UI_UNIT_X;
}
/**
* Action to run when clicking in the outliner,
*
@@ -1365,6 +1507,9 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
if (outliner_is_co_within_restrict_columns(space_outliner, region, view_mval[0])) {
return OPERATOR_CANCELLED;
}
else if (outliner_is_co_within_mode_column(space_outliner, view_mval)) {
return OPERATOR_CANCELLED;
}
if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
if (deselect_all) {
@@ -1378,7 +1523,8 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
else {
/* The row may also contain children, if one is hovered we want this instead of current te. */
/* 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(
space_outliner, te, view_mval[0], &merged_elements);
@@ -1403,7 +1549,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) |
(is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) |
(extend ? OL_ITEM_EXTEND : 0) | OL_ITEM_TOGGLE_MODE;
(extend ? OL_ITEM_EXTEND : 0);
outliner_item_select(C, space_outliner, activate_te, select_flag);
}
@@ -1532,6 +1678,10 @@ static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
if (outliner_is_co_within_mode_column(space_outliner, view_mval)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
return WM_gesture_box_invoke(C, op, event);
}
@@ -1630,6 +1780,40 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr
return te;
}
static TreeElement *outliner_walk_left(SpaceOutliner *space_outliner,
TreeElement *te,
bool toggle_all)
{
TreeStoreElem *tselem = TREESTORE(te);
if (TSELEM_OPEN(tselem, space_outliner)) {
outliner_item_openclose(te, false, toggle_all);
}
/* Only walk up a level if the element is closed and not toggling expand */
else if (!toggle_all && te->parent) {
te = te->parent;
}
return te;
}
static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner,
TreeElement *te,
bool toggle_all)
{
TreeStoreElem *tselem = TREESTORE(te);
/* Only walk down a level if the element is open and not toggling expand */
if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
te = te->subtree.first;
}
else {
outliner_item_openclose(te, true, toggle_all);
}
return te;
}
static TreeElement *do_outliner_select_walk(SpaceOutliner *space_outliner,
TreeElement *te,
const int direction,
@@ -1646,10 +1830,10 @@ static TreeElement *do_outliner_select_walk(SpaceOutliner *space_outliner,
te = outliner_find_next_element(space_outliner, te);
break;
case UI_SELECT_WALK_LEFT:
outliner_item_openclose(te, false, toggle_all);
te = outliner_walk_left(space_outliner, te, toggle_all);
break;
case UI_SELECT_WALK_RIGHT:
outliner_item_openclose(te, true, toggle_all);
te = outliner_walk_right(space_outliner, te, toggle_all);
break;
}

View File

@@ -95,110 +95,105 @@
/** \name ID/Library/Data Set/Un-link Utilities
* \{ */
static void set_operation_types(SpaceOutliner *space_outliner,
ListBase *lb,
int *scenelevel,
int *objectlevel,
int *idlevel,
int *datalevel)
static void get_element_operation_type(
TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel)
{
TreeElement *te;
TreeStoreElem *tselem;
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
/* Layer collection points to collection ID. */
if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
if (*datalevel == 0) {
*datalevel = tselem->type;
}
else if (*datalevel != tselem->type) {
*datalevel = -1;
}
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
/* Layer collection points to collection ID. */
if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
if (*datalevel == 0) {
*datalevel = tselem->type;
}
else {
const int idcode = (int)GS(tselem->id->name);
bool is_standard_id = false;
switch ((ID_Type)idcode) {
case ID_SCE:
*scenelevel = 1;
break;
case ID_OB:
*objectlevel = 1;
break;
case ID_ME:
case ID_CU:
case ID_MB:
case ID_LT:
case ID_LA:
case ID_AR:
case ID_CA:
case ID_SPK:
case ID_MA:
case ID_TE:
case ID_IP:
case ID_IM:
case ID_SO:
case ID_KE:
case ID_WO:
case ID_AC:
case ID_TXT:
case ID_GR:
case ID_LS:
case ID_LI:
case ID_VF:
case ID_NT:
case ID_BR:
case ID_PA:
case ID_GD:
case ID_MC:
case ID_MSK:
case ID_PAL:
case ID_PC:
case ID_CF:
case ID_WS:
case ID_LP:
case ID_HA:
case ID_PT:
case ID_VO:
case ID_SIM:
is_standard_id = true;
break;
case ID_WM:
case ID_SCR:
/* Those are ignored here. */
/* Note: while Screens should be manageable here, deleting a screen used by a workspace
* will cause crashes when trying to use that workspace, so for now let's play minimal,
* safe change. */
break;
}
if (idcode == ID_NLA) {
/* Fake one, not an actual ID type... */
is_standard_id = true;
}
if (is_standard_id) {
if (*idlevel == 0) {
*idlevel = idcode;
}
else if (*idlevel != idcode) {
*idlevel = -1;
}
if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) {
*datalevel = 0;
}
}
else if (*datalevel != tselem->type) {
*datalevel = -1;
}
}
if (TSELEM_OPEN(tselem, space_outliner)) {
set_operation_types(
space_outliner, &te->subtree, scenelevel, objectlevel, idlevel, datalevel);
else {
const int idcode = (int)GS(tselem->id->name);
bool is_standard_id = false;
switch ((ID_Type)idcode) {
case ID_SCE:
*scenelevel = 1;
break;
case ID_OB:
*objectlevel = 1;
break;
case ID_ME:
case ID_CU:
case ID_MB:
case ID_LT:
case ID_LA:
case ID_AR:
case ID_CA:
case ID_SPK:
case ID_MA:
case ID_TE:
case ID_IP:
case ID_IM:
case ID_SO:
case ID_KE:
case ID_WO:
case ID_AC:
case ID_TXT:
case ID_GR:
case ID_LS:
case ID_LI:
case ID_VF:
case ID_NT:
case ID_BR:
case ID_PA:
case ID_GD:
case ID_MC:
case ID_MSK:
case ID_PAL:
case ID_PC:
case ID_CF:
case ID_WS:
case ID_LP:
case ID_HA:
case ID_PT:
case ID_VO:
case ID_SIM:
is_standard_id = true;
break;
case ID_WM:
case ID_SCR:
/* Those are ignored here. */
/* Note: while Screens should be manageable here, deleting a screen used by a workspace
* will cause crashes when trying to use that workspace, so for now let's play minimal,
* safe change. */
break;
}
if (idcode == ID_NLA) {
/* Fake one, not an actual ID type... */
is_standard_id = true;
}
if (is_standard_id) {
if (*idlevel == 0) {
*idlevel = idcode;
}
else if (*idlevel != idcode) {
*idlevel = -1;
}
if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) {
*datalevel = 0;
}
}
}
}
}
static TreeElement *get_target_element(SpaceOutliner *space_outliner)
{
TreeElement *te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
BLI_assert(te);
return te;
}
static void unlink_action_fn(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -405,7 +400,8 @@ static void outliner_do_libdata_operation(bContext *C,
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
if (tselem->flag & TSE_SELECTED) {
if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
/* TODO (Nathan): Why is TSE_LAYER_COLLECTION an exception here? */
if ((tselem->type == 0 && te->idcode != 0) /* || tselem->type == TSE_LAYER_COLLECTION*/) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
}
@@ -1407,8 +1403,6 @@ enum {
OL_OP_TOGSEL,
OL_OP_TOGREN,
OL_OP_RENAME,
OL_OP_OBJECT_MODE_ENTER,
OL_OP_OBJECT_MODE_EXIT,
};
static const EnumPropertyItem prop_object_op_types[] = {
@@ -1421,8 +1415,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
"Remap Users",
"Make all users of selected data-blocks to use instead a new chosen one"},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
{OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""},
{OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -1492,16 +1484,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
str = "Rename Object";
}
else if (event == OL_OP_OBJECT_MODE_ENTER) {
outliner_do_object_operation(
C, op->reports, scene, space_outliner, &space_outliner->tree, item_object_mode_enter_fn);
str = "Enter Current Mode";
}
else if (event == OL_OP_OBJECT_MODE_EXIT) {
outliner_do_object_operation(
C, op->reports, scene, space_outliner, &space_outliner->tree, item_object_mode_exit_fn);
str = "Exit Current Mode";
}
else {
BLI_assert(0);
return OPERATOR_CANCELLED;
@@ -1805,18 +1787,16 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutlinerIdOpTypes event;
/* check for invalid states */
if (space_outliner == NULL) {
return OPERATOR_CANCELLED;
}
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
event = RNA_enum_get(op->ptr, "type");
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
eOutlinerIdOpTypes event = RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_IDOP_UNLINK: {
/* unlink datablock from its parent */
@@ -2137,18 +2117,16 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutlinerLibOpTypes event;
/* check for invalid states */
if (space_outliner == NULL) {
return OPERATOR_CANCELLED;
}
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
event = RNA_enum_get(op->ptr, "type");
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
eOutlinerLibOpTypes event = RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_RENAME: {
outliner_do_libdata_operation(
@@ -2270,8 +2248,9 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
if (space_outliner == NULL) {
return OPERATOR_CANCELLED;
}
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
/* get action to use */
act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"));
@@ -2378,22 +2357,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
wmWindowManager *wm = CTX_wm_manager(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutliner_AnimDataOps event;
/* check for invalid states */
if (space_outliner == NULL) {
return OPERATOR_CANCELLED;
}
event = RNA_enum_get(op->ptr, "type");
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
if (datalevel != TSE_ANIM_DATA) {
return OPERATOR_CANCELLED;
}
/* perform the core operation */
eOutliner_AnimDataOps event = RNA_enum_get(op->ptr, "type");
switch (event) {
case OUTLINER_ANIMOP_CLEAR_ADT:
/* Remove Animation Data - this may remove the active action, in some cases... */
@@ -2483,15 +2461,10 @@ static const EnumPropertyItem prop_constraint_op_types[] = {
static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutliner_PropConstraintOps event;
event = RNA_enum_get(op->ptr, "type");
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
eOutliner_PropConstraintOps event = RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, datalevel, event, &space_outliner->tree, constraint_fn, C);
space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C);
if (event == OL_CONSTRAINTOP_DELETE) {
outliner_cleanup_tree(space_outliner);
@@ -2535,15 +2508,10 @@ static const EnumPropertyItem prop_modifier_op_types[] = {
static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutliner_PropModifierOps event;
event = RNA_enum_get(op->ptr, "type");
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
eOutliner_PropModifierOps event = RNA_enum_get(op->ptr, "type");
outliner_do_data_operation(
space_outliner, datalevel, event, &space_outliner->tree, modifier_fn, C);
space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C);
if (event == OL_MODIFIER_OP_DELETE) {
outliner_cleanup_tree(space_outliner);
@@ -2590,17 +2558,16 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutliner_PropDataOps event;
/* check for invalid states */
if (space_outliner == NULL) {
return OPERATOR_CANCELLED;
}
event = RNA_enum_get(op->ptr, "type");
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
TreeElement *te = get_target_element(space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
eOutliner_PropDataOps event = RNA_enum_get(op->ptr, "type");
switch (datalevel) {
case TSE_POSE_CHANNEL: {
outliner_do_data_operation(
@@ -2687,7 +2654,7 @@ static int outliner_operator_menu(bContext *C, const char *opname)
/* set this so the default execution context is the same as submenus */
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop));
uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop), false);
uiItemS(layout);
@@ -2699,134 +2666,117 @@ static int outliner_operator_menu(bContext *C, const char *opname)
}
static int do_outliner_operation_event(bContext *C,
ReportList *reports,
ARegion *region,
SpaceOutliner *space_outliner,
TreeElement *te,
const float mval[2])
TreeElement *te)
{
ReportList *reports = CTX_wm_reports(C); /* XXX... */
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
TreeStoreElem *tselem = TREESTORE(te);
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
TreeStoreElem *tselem = TREESTORE(te);
/* select object that's clicked on and popup context menu */
if (!(tselem->flag & TSE_SELECTED)) {
if (outliner_flag_is_any_test(&space_outliner->tree, TSE_SELECTED, 1)) {
outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
}
tselem->flag |= TSE_SELECTED;
/* Only redraw, don't rebuild here because TreeElement pointers will
* become invalid and operations will crash. */
ED_region_tag_redraw_no_rebuild(region);
ED_outliner_select_sync_from_outliner(C, space_outliner);
}
set_operation_types(
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
if (scenelevel) {
if (objectlevel || datalevel || idlevel) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
return OPERATOR_CANCELLED;
}
return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
}
if (objectlevel) {
WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
}
if (idlevel) {
if (idlevel == -1 || datalevel) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
return OPERATOR_CANCELLED;
}
switch (idlevel) {
case ID_GR:
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
break;
case ID_LI:
return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
break;
default:
return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
break;
}
}
else if (datalevel) {
if (datalevel == -1) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
return OPERATOR_CANCELLED;
}
if (datalevel == TSE_ANIM_DATA) {
return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
}
if (datalevel == TSE_DRIVER_BASE) {
/* do nothing... no special ops needed yet */
return OPERATOR_CANCELLED;
}
if (datalevel == TSE_LAYER_COLLECTION) {
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
}
if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
}
if (datalevel == TSE_ID_BASE) {
/* do nothing... there are no ops needed here yet */
return 0;
}
if (datalevel == TSE_CONSTRAINT) {
return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
}
if (datalevel == TSE_MODIFIER) {
return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
}
return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
}
return 0;
int clear_flag = TSE_ACTIVE;
if (!(tselem->flag & TSE_SELECTED)) {
clear_flag |= TSE_SELECTED;
}
for (te = te->subtree.first; te; te = te->next) {
int retval = do_outliner_operation_event(C, region, space_outliner, te, mval);
if (retval) {
return retval;
outliner_flag_set(&space_outliner->tree, clear_flag, false);
tselem->flag |= TSE_SELECTED | TSE_ACTIVE;
/* Only redraw, don't rebuild here because TreeElement pointers will
* become invalid and operations will crash. */
ED_region_tag_redraw_no_rebuild(region);
ED_outliner_select_sync_from_outliner(C, space_outliner);
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
if (scenelevel) {
if (objectlevel || datalevel || idlevel) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
return OPERATOR_CANCELLED;
}
return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
}
if (objectlevel) {
WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
}
if (idlevel) {
if (idlevel == -1 || datalevel) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
return OPERATOR_CANCELLED;
}
switch (idlevel) {
case ID_GR:
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
break;
case ID_LI:
return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
break;
default:
return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
break;
}
}
else if (datalevel) {
if (datalevel == -1) {
BKE_report(reports, RPT_WARNING, "Mixed selection");
return OPERATOR_CANCELLED;
}
if (datalevel == TSE_ANIM_DATA) {
return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
}
if (datalevel == TSE_DRIVER_BASE) {
/* do nothing... no special ops needed yet */
return OPERATOR_CANCELLED;
}
if (datalevel == TSE_LAYER_COLLECTION) {
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
}
if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
return OPERATOR_FINISHED;
}
if (datalevel == TSE_ID_BASE) {
/* do nothing... there are no ops needed here yet */
return 0;
}
if (datalevel == TSE_CONSTRAINT) {
return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
}
if (datalevel == TSE_MODIFIER) {
return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
}
return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
}
return 0;
}
static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
uiBut *but = UI_context_active_but_get(C);
TreeElement *te;
float fmval[2];
float view_mval[2];
if (but) {
UI_but_tooltip_timer_remove(C, but);
}
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
UI_view2d_region_to_view(
&region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
for (te = space_outliner->tree.first; te; te = te->next) {
int retval = do_outliner_operation_event(C, region, space_outliner, te, fmval);
if (retval) {
return retval;
}
TreeElement *hovered_te = outliner_find_item_at_y(
space_outliner, &space_outliner->tree, view_mval[1]);
if (!hovered_te) {
/* Let this fall through to 'OUTLINER_MT_context_menu'. */
return OPERATOR_PASS_THROUGH;
}
/* Let this fall through to 'OUTLINER_MT_context_menu'. */
return OPERATOR_PASS_THROUGH;
return do_outliner_operation_event(C, op->reports, region, space_outliner, hovered_te);
}
/* Menu only! Calls other operators */

View File

@@ -32,6 +32,7 @@
#include "DNA_camera_types.h"
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_hair_types.h"
#include "DNA_key_types.h"
@@ -46,6 +47,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
#include "DNA_simulation_types.h"
#include "DNA_speaker_types.h"
#include "DNA_volume_types.h"
@@ -552,6 +554,72 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
}
/* Grease Pencil modifiers. */
if (!BLI_listbase_is_empty(&ob->greasepencil_modifiers)) {
GpencilModifierData *md;
TreeElement *ten_mod = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
int index;
ten_mod->name = IFACE_("Modifiers");
for (index = 0, md = ob->greasepencil_modifiers.first; md; index++, md = md->next) {
TreeElement *ten = outliner_add_element(
space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
ten->name = md->name;
ten->directdata = md;
if (md->type == eGpencilModifierType_Armature) {
outliner_add_element(space_outliner,
&ten->subtree,
((ArmatureGpencilModifierData *)md)->object,
ten,
TSE_LINKED_OB,
0);
}
else if (md->type == eGpencilModifierType_Hook) {
outliner_add_element(space_outliner,
&ten->subtree,
((HookGpencilModifierData *)md)->object,
ten,
TSE_LINKED_OB,
0);
}
else if (md->type == eGpencilModifierType_Lattice) {
outliner_add_element(space_outliner,
&ten->subtree,
((LatticeGpencilModifierData *)md)->object,
ten,
TSE_LINKED_OB,
0);
}
}
}
/* Grease Pencil effects. */
if (!BLI_listbase_is_empty(&ob->shader_fx)) {
ShaderFxData *fx;
TreeElement *ten_fx = outliner_add_element(
space_outliner, &te->subtree, ob, te, TSE_EFFECT_BASE, 0);
int index;
ten_fx->name = IFACE_("Effects");
for (index = 0, fx = ob->shader_fx.first; fx; index++, fx = fx->next) {
TreeElement *ten = outliner_add_element(
space_outliner, &ten_fx->subtree, ob, ten_fx, TSE_EFFECT, index);
ten->name = fx->name;
ten->directdata = fx;
if (fx->type == eShaderFxType_Swirl) {
outliner_add_element(space_outliner,
&ten->subtree,
((SwirlShaderFxData *)fx)->object,
ten,
TSE_LINKED_OB,
0);
}
}
}
/* vertex groups */
if (ob->defbase.first) {
bDeformGroup *defgroup;
@@ -1787,117 +1855,24 @@ static int treesort_alpha(const void *v1, const void *v2)
return 0;
}
/* this is nice option for later? doesn't look too useful... */
#if 0
static int treesort_obtype_alpha(const void *v1, const void *v2)
static int treesort_type(const void *v1, const void *v2)
{
const tTreeSort *x1 = v1, *x2 = v2;
const tTreeSort *x1 = v1;
const tTreeSort *x2 = v2;
/* first put objects last (hierarchy) */
if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
return 1;
}
else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
else if (((Object *)x2->id)->type > ((Object *)x1->id)->type) {
return -1;
}
else {
/* 2nd we check ob type */
if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
return 1;
}
else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
return -1;
}
else {
return 0;
}
}
else {
int comp = BLI_strcasecmp_natural(x1->name, x2->name);
if (comp > 0) {
return 1;
}
else if (comp < 0) {
return -1;
}
return 0;
}
}
}
#endif
/* sort happens on each subtree individual */
static void outliner_sort(ListBase *lb)
{
TreeElement *te;
TreeStoreElem *tselem;
te = lb->last;
if (te == NULL) {
return;
}
tselem = TREESTORE(te);
/* sorting rules; only object lists, ID lists, or deformgroups */
if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
(tselem->type == 0 && te->idcode == ID_OB)) {
int totelem = BLI_listbase_count(lb);
if (totelem > 1) {
tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
tTreeSort *tp = tear;
int skip = 0;
for (te = lb->first; te; te = te->next, tp++) {
tselem = TREESTORE(te);
tp->te = te;
tp->name = te->name;
tp->idcode = te->idcode;
if (tselem->type && tselem->type != TSE_DEFGROUP) {
tp->idcode = 0; /* Don't sort this. */
}
if (tselem->type == TSE_ID_BASE) {
tp->idcode = 1; /* Do sort this. */
}
tp->id = tselem->id;
}
/* just sort alphabetically */
if (tear->idcode == 1) {
qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
}
else {
/* keep beginning of list */
for (tp = tear, skip = 0; skip < totelem; skip++, tp++) {
if (tp->idcode) {
break;
}
}
if (skip < totelem) {
qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
}
}
BLI_listbase_clear(lb);
tp = tear;
while (totelem--) {
BLI_addtail(lb, tp->te);
tp++;
}
MEM_freeN(tear);
}
}
for (te = lb->first; te; te = te->next) {
outliner_sort(&te->subtree);
/* Compare by name */
return treesort_alpha(v1, v2);
}
}
/* TODO (Nathan): Should children still be sorted? */
static void outliner_collections_children_sort(ListBase *lb)
{
TreeElement *te;
@@ -1942,6 +1917,126 @@ static void outliner_collections_children_sort(ListBase *lb)
}
}
static bool outliner_is_sort_item(TreeElement *te)
{
TreeStoreElem *tselem = TREESTORE(te);
return (tselem->type == 0 && te->idcode == ID_OB) || outliner_is_collection_tree_element(te) ||
(ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL));
}
/* Sort collections and objects separately on each outliner subtree. */
static void outliner_tree_sort(SpaceOutliner *space_outliner, ListBase *tree)
{
if (BLI_listbase_is_empty(tree)) {
return;
}
TreeElement *te_last = tree->last;
TreeStoreElem *tselem;
/* Only sort collections and objects */
if (outliner_is_sort_item(te_last)) {
int num_elems = BLI_listbase_count(tree);
if (num_elems > 1) {
tTreeSort *tree_sort = MEM_mallocN(num_elems * sizeof(tTreeSort), "tree sort array");
tTreeSort *tree_sort_p = tree_sort;
int num_collections = 0;
for (TreeElement *te = tree->first; te; te = te->next, tree_sort_p++) {
tselem = TREESTORE(te);
tree_sort_p->te = te;
tree_sort_p->name = te->name;
tree_sort_p->idcode = te->idcode;
if (tselem->type && tselem->type != TSE_DEFGROUP) {
tree_sort_p->idcode = 0; /* Don't sort this. */
}
if (tselem->type == TSE_ID_BASE) {
tree_sort_p->idcode = 1; /* Do sort this. */
}
if (outliner_is_collection_tree_element(te)) {
num_collections++;
}
tree_sort_p->id = tselem->id;
}
/* Skip beginning of list */
int skip = 0;
if (!outliner_is_sort_item(tree_sort->te)) {
for (tree_sort_p = tree_sort, skip = 0; skip < num_elems; skip++, tree_sort_p++) {
if (outliner_is_sort_item(tree_sort_p->te)) {
break;
}
}
}
/* Sort collections. */
if (num_collections > 0) {
switch (space_outliner->sort_method) {
case SO_SORT_ALPHA:
qsort(tree_sort + skip, num_collections - skip, sizeof(tTreeSort), treesort_alpha);
break;
case SO_SORT_TYPE:
qsort(tree_sort + skip, num_collections - skip, sizeof(tTreeSort), treesort_alpha);
break;
}
}
/* Sort objects. */
if (num_elems - num_collections - skip > 0) {
switch (space_outliner->sort_method) {
case SO_SORT_ALPHA:
qsort(tree_sort + skip + num_collections,
num_elems - num_collections - skip,
sizeof(tTreeSort),
treesort_alpha);
break;
case SO_SORT_TYPE:
qsort(tree_sort + skip + num_collections,
num_elems - num_collections - skip,
sizeof(tTreeSort),
treesort_type);
break;
}
}
/* Copy sorted list back into tree */
BLI_listbase_clear(tree);
tree_sort_p = tree_sort;
while (num_elems--) {
BLI_addtail(tree, tree_sort_p->te);
tree_sort_p++;
}
MEM_freeN(tree_sort);
}
}
LISTBASE_FOREACH (TreeElement *, te, tree) {
outliner_tree_sort(space_outliner, &te->subtree);
}
}
#if 0
void f(SpaceOutliner *space_outliner)
{
if (space_outliner->sort_method == SO_SORT_ALPHA) {
outliner_sort(tree);
}
else if (space_outliner->sort_method == SO_SORT_TYPE) {
}
else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) {
/* We group the children that are in the collection before the ones that are not.
* This way we can try to draw them in a different style altogether.
* We also have to respect the original order of the elements in case alphabetical
* sorting is not enabled. This keep object data and modifiers before its children. */
outliner_collections_children_sort(tree);
}
}
#endif
/* Filtering ----------------------------------------------- */
typedef struct OutlinerTreeElementFocus {
@@ -2564,15 +2659,8 @@ void outliner_build_tree(Main *mainvar,
}
}
if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) {
outliner_sort(&space_outliner->tree);
}
else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) {
/* We group the children that are in the collection before the ones that are not.
* This way we can try to draw them in a different style altogether.
* We also have to respect the original order of the elements in case alphabetical
* sorting is not enabled. This keep object data and modifiers before its children. */
outliner_collections_children_sort(&space_outliner->tree);
if (space_outliner->sort_method != SO_SORT_FREE) {
outliner_tree_sort(space_outliner, &space_outliner->tree);
}
outliner_filter_tree(space_outliner, view_layer);

View File

@@ -359,6 +359,9 @@ float outliner_restrict_columns_width(const SpaceOutliner *space_outliner)
num_columns = 3;
break;
case SO_VIEW_LAYER:
if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
num_columns++;
}
if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
num_columns++;
}

View File

@@ -305,7 +305,7 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
space_outliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE;
space_outliner->outlinevis = SO_VIEW_LAYER;
space_outliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
space_outliner->flag |= SO_SYNC_SELECT;
space_outliner->flag = SO_SYNC_SELECT | SO_MODE_COLUMN;
/* header */
region = MEM_callocN(sizeof(ARegion), "header for outliner");

View File

@@ -187,7 +187,7 @@ static int select_orientation_invoke(bContext *C,
pup = UI_popup_menu_begin(C, IFACE_("Orientation"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation");
uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation", false);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;

View File

@@ -58,7 +58,9 @@ typedef struct Collection {
short flag;
/* Runtime-only, always cleared on file load. */
short tag;
char _pad[4];
short color;
char _pad[2];
/* Runtime. Cache of objects in this collection and all its
* children. This is created on demand when e.g. some physics
@@ -92,3 +94,16 @@ enum {
* Using a generic tag like LIB_TAG_DOIT for this is just impossible, we need our very own. */
COLLECTION_TAG_RELATION_REBUILD = (1 << 0),
};
/* Collection->color */
enum {
COLLECTION_COLOR_NONE = 0,
COLLECTION_COLOR_01 = 1,
COLLECTION_COLOR_02 = 2,
COLLECTION_COLOR_03 = 3,
COLLECTION_COLOR_04 = 4,
COLLECTION_COLOR_05 = 5,
COLLECTION_COLOR_06 = 6,
COLLECTION_COLOR_07 = 7,
COLLECTION_COLOR_08 = 8,
};

View File

@@ -109,6 +109,8 @@ enum {
#define TSE_SCENE_COLLECTION_BASE 39
#define TSE_VIEW_COLLECTION_BASE 40
#define TSE_SCENE_OBJECTS_BASE 41
#define TSE_EFFECT_BASE 42
#define TSE_EFFECT 43
/* Check whether given TreeStoreElem should have a real ID in its ->id member. */
#define TSE_IS_REAL_ID(_tse) \

View File

@@ -274,6 +274,9 @@ typedef struct SpaceOutliner {
* Pointers to treestore elements, grouped by (id, type, nr)
* in hashtable for faster searching */
void *treehash;
char sort_method;
char _pad[7];
} SpaceOutliner;
/* SpaceOutliner.flag */
@@ -282,8 +285,9 @@ typedef enum eSpaceOutliner_Flag {
/* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */
SO_FLAG_UNUSED_1 = (1 << 2), /* cleared */
/* SO_HIDE_KEYINGSETINFO = (1 << 3), */ /* UNUSED */
SO_SKIP_SORT_ALPHA = (1 << 4),
/* SO_SKIP_SORT_ALPHA = (1 << 4), */ /* UNUSED */
SO_SYNC_SELECT = (1 << 5),
SO_MODE_COLUMN = (1 << 6),
} eSpaceOutliner_Flag;
/* SpaceOutliner.filter */
@@ -294,7 +298,7 @@ typedef enum eSpaceOutliner_Filter {
SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */
SO_FILTER_NO_CHILDREN = (1 << 4),
SO_FILTER_UNUSED_5 = (1 << 5), /* cleared */
SO_FILTER_NO_ROW_CHILDREN = (1 << 5),
SO_FILTER_NO_OB_MESH = (1 << 6),
SO_FILTER_NO_OB_ARMATURE = (1 << 7),
SO_FILTER_NO_OB_EMPTY = (1 << 8),
@@ -321,8 +325,8 @@ typedef enum eSpaceOutliner_Filter {
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 | \
SO_FILTER_NO_COLLECTION)
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_NO_ROW_CHILDREN | \
SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | SO_FILTER_NO_COLLECTION)
/* SpaceOutliner.filter_state */
typedef enum eSpaceOutliner_StateFilter {
@@ -381,6 +385,13 @@ typedef enum eSpaceOutliner_Search_Flags {
SO_SEARCH_RECURSIVE = (1 << 2),
} eSpaceOutliner_Search_Flags;
/* SpaceOutliner.sort_method */
typedef enum eSpaceOutliner_Sort_Types {
SO_SORT_FREE,
SO_SORT_ALPHA,
SO_SORT_TYPE,
} eSpaceOutliner_Sort_Types;
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -455,6 +455,10 @@ typedef enum eWireColor_Flags {
/* TH_WIRECOLOR_TEXTCOLS = (1 << 1), */ /* UNUSED */
} eWireColor_Flags;
typedef struct ThemeCollectionColor {
unsigned char color[4];
} ThemeCollectionColor;
/**
* A theme.
*
@@ -493,6 +497,8 @@ typedef struct bTheme {
ThemeWireColor tarm[20];
/*ThemeWireColor tobj[20];*/
ThemeCollectionColor collection_color[8];
int active_theme_area;
char _pad0[4];
} bTheme;

View File

@@ -633,6 +633,7 @@ extern StructRNA RNA_TextureNodeViewer;
extern StructRNA RNA_TextureSlot;
extern StructRNA RNA_Theme;
extern StructRNA RNA_ThemeBoneColorSet;
extern StructRNA RNA_ThemeCollectionColor;
extern StructRNA RNA_ThemeConsole;
extern StructRNA RNA_ThemeDopeSheet;
extern StructRNA RNA_ThemeFileBrowser;

View File

@@ -229,6 +229,8 @@ extern const EnumPropertyItem rna_enum_context_mode_items[];
extern const EnumPropertyItem rna_enum_curveprofile_preset_items[];
extern const EnumPropertyItem rna_enum_preference_section_items[];
extern const EnumPropertyItem rna_enum_collection_color_items[];
/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
int rna_node_tree_idname_to_enum(const char *idname);

View File

@@ -30,6 +30,19 @@
#include "WM_types.h"
const EnumPropertyItem rna_enum_collection_color_items[] = {
{COLLECTION_COLOR_NONE, "NONE", ICON_X, "None", "Assign no color tag to the collection"},
{COLLECTION_COLOR_01, "COLOR_01", ICON_COLLECTION_COLOR_01, "Color 01", ""},
{COLLECTION_COLOR_02, "COLOR_02", ICON_COLLECTION_COLOR_02, "Color 02", ""},
{COLLECTION_COLOR_03, "COLOR_03", ICON_COLLECTION_COLOR_03, "Color 03", ""},
{COLLECTION_COLOR_04, "COLOR_04", ICON_COLLECTION_COLOR_04, "Color 04", ""},
{COLLECTION_COLOR_05, "COLOR_05", ICON_COLLECTION_COLOR_05, "Color 05", ""},
{COLLECTION_COLOR_06, "COLOR_06", ICON_COLLECTION_COLOR_06, "Color 06", ""},
{COLLECTION_COLOR_07, "COLOR_07", ICON_COLLECTION_COLOR_07, "Color 07", ""},
{COLLECTION_COLOR_08, "COLOR_08", ICON_COLLECTION_COLOR_08, "Color 08", ""},
{0, NULL, 0, NULL, NULL},
};
#ifdef RNA_RUNTIME
# include "DNA_object_types.h"
@@ -474,6 +487,12 @@ void RNA_def_collections(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
prop = RNA_def_property(srna, "color", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color");
RNA_def_property_enum_items(prop, rna_enum_collection_color_items);
RNA_def_property_ui_text(prop, "Collection Color", "Color tag for a collection");
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
RNA_define_lib_overridable(false);
}

View File

@@ -2984,6 +2984,13 @@ static void rna_def_space_outliner(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem sort_method_items[] = {
{SO_SORT_FREE, "FREE", 0, "Manual", "Sort objects and collections manually"},
{SO_SORT_ALPHA, "ALPHA", 0, "Name", "Sort objects and collections by name alphabetically"},
{SO_SORT_TYPE, "TYPE", 0, "Type", "Sort objects by type"},
{0, NULL, 0, NULL, NULL},
};
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"},
@@ -3021,9 +3028,10 @@ static void rna_def_space_outliner(BlenderRNA *brna)
prop, "Complete Matches Only", "Only use complete matches of search string");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_sort_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_SKIP_SORT_ALPHA);
RNA_def_property_ui_text(prop, "Sort Alphabetically", "");
prop = RNA_def_property(srna, "sort_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "sort_method");
RNA_def_property_enum_items(prop, sort_method_items);
RNA_def_property_ui_text(prop, "Sort Type", "Outliner sort method");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_sync_select", PROP_BOOLEAN, PROP_NONE);
@@ -3032,6 +3040,12 @@ static void rna_def_space_outliner(BlenderRNA *brna)
prop, "Sync Outliner Selection", "Sync outliner selection with other editors");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "show_mode_column", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SO_MODE_COLUMN);
RNA_def_property_ui_text(
prop, "Show Mode Column", "Show the mode column for mode toggle and activation");
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);
@@ -3092,6 +3106,11 @@ static void rna_def_space_outliner(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Object Children", "Show children");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_filter_row_children", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_ROW_CHILDREN);
RNA_def_property_ui_text(prop, "Show Row Children", "Show children on collapsed rows");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
prop = RNA_def_property(srna, "use_filter_collection", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_COLLECTION);
RNA_def_property_ui_text(prop, "Show Collections", "Show collections");

View File

@@ -977,6 +977,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in buttons, no text");
func = RNA_def_function(srna, "operator_menu_enum", "rna_uiItemMenuEnumO");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);

View File

@@ -3615,6 +3615,23 @@ static void rna_def_userdef_theme_colorset(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
static void rna_def_userdef_theme_collection_color(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ThemeCollectionColor", NULL);
RNA_def_struct_sdna(srna, "ThemeCollectionColor");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "Theme Collection Color", "Theme settings for collection colors");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "color");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "Collection Color Tag");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3931,6 +3948,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "tarm", "");
RNA_def_property_struct_type(prop, "ThemeBoneColorSet");
RNA_def_property_ui_text(prop, "Bone Color Sets", "");
prop = RNA_def_property(srna, "collection_color", PROP_COLLECTION, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_collection_sdna(prop, NULL, "collection_color", "");
RNA_def_property_struct_type(prop, "ThemeCollectionColor");
RNA_def_property_ui_text(prop, "Collection Color", "");
}
static void rna_def_userdef_addon(BlenderRNA *brna)
@@ -4172,6 +4195,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna)
rna_def_userdef_theme_space_topbar(brna);
rna_def_userdef_theme_space_statusbar(brna);
rna_def_userdef_theme_colorset(brna);
rna_def_userdef_theme_collection_color(brna);
rna_def_userdef_themes(brna);
}

View File

@@ -3991,6 +3991,12 @@ static const EnumPropertyItem *rna_id_itemf(bContext *UNUSED(C),
if (local == false || !ID_IS_LINKED(id)) {
item_tmp.identifier = item_tmp.name = id->name + 2;
item_tmp.value = i++;
/* Show collection color tag icons in menus. */
if (GS(id->name) == ID_GR) {
item_tmp.icon = UI_collection_color_icon_get((Collection *)id);
}
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
}